]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.14pre13 2.2.14pre13
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:20:27 +0000 (15:20 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:20:27 +0000 (15:20 -0500)
o Cure SMP deadlock on non DMA ide disk (Alan Cox)
o Change argument copying for mount (needed for
Davem's sparc64) (Alan Cox)
o Fix missing tlb flushes on vmscan (Dave Miller)
o Account always defragment off as well as on (Julian Anastasov)
o Fix APIC handling with short form table (Eirik Fuller)
o GDTH driver update   (ICP Vortex)
o Finish fixing the AX.25 socket bug (Tomi Manninen)
o QlogicFC driver update (Chris Loveland)
o New Tlan maintainer (Torben Mathiasen)
o Hopefully fix the NFS submount bug (Trond Myklebust)
o Fix mem= on Alpha (Jay Estabrook)
o Allow hiding interfaces from global arp (Alexey Kuznetsov &
o IPV6 autoconfig for non ethernet  Julian Anastasov)
o event is now global_event, the export defined
made a horrible mess of local variable/structs
when debugging with source (Alan Cox)

61 files changed:
Documentation/networking/ip-sysctl.txt
Documentation/proc.txt
Documentation/sound/NM256
MAINTAINERS
Makefile
arch/alpha/mm/init.c
arch/i386/kernel/smp.c
drivers/block/ide-disk.c
drivers/block/loop.c
drivers/net/tlan.c
drivers/net/tlan.h
drivers/scsi/gdth.c
drivers/scsi/gdth.h
drivers/scsi/gdth_ioctl.h
drivers/scsi/gdth_proc.c
drivers/scsi/gdth_proc.h
drivers/scsi/qlogicfc.c
drivers/sound/ac97.c
drivers/sound/ac97.h
drivers/sound/nm256.h
drivers/sound/nm256_audio.c
drivers/sound/nm256_coeff.h
fs/adfs/inode.c
fs/affs/inode.c
fs/affs/namei.c
fs/dcache.c
fs/ext2/file.c
fs/ext2/inode.c
fs/ext2/namei.c
fs/fat/inode.c
fs/file_table.c
fs/hfs/dir.c
fs/minix/namei.c
fs/msdos/namei.c
fs/nfs/dir.c
fs/nfs/inode.c
fs/read_write.c
fs/super.c
fs/ufs/file.c
fs/ufs/inode.c
fs/ufs/namei.c
fs/vfat/namei.c
include/linux/dcache.h
include/linux/errqueue.h
include/linux/if.h
include/linux/inetdevice.h
include/linux/ip.h
include/linux/netdevice.h
include/linux/rtnetlink.h
include/linux/sched.h
include/linux/socket.h
include/linux/sysctl.h
kernel/ksyms.c
kernel/sched.c
mm/vmscan.c
net/ax25/af_ax25.c
net/bridge/br.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/ip_masq.c
net/ipv6/addrconf.c

index 8def0e7fc2b747dcaeb192deeb40537fa7f46577..208b7a0f162137259d862fa844e1b1a837eb27e4 100644 (file)
@@ -156,6 +156,14 @@ mc_forwarding - BOOLEAN
 proxy_arp - BOOLEAN
        Do proxy arp.
 
+hidden - BOOLEAN
+       Hide addresses attached to this device from another devices.
+       Such addresses will never be selected by source address autoselection
+       mechanism, host does not answer broadcast ARP requests for them,
+       does not announce it as source address of ARP requests, but they
+       are still reachable via IP. This flag is activated only if it is
+       enabled both in specific device section and in "all" section.
+
 shared_media - BOOLEAN
        undocumented.
 
index 5f5c20f2fc9c379d750a074b465995df17e1f885..bc5e55f37db2b0ecefb05d363667e3eb185eade9 100644 (file)
@@ -1192,6 +1192,14 @@ secure_redirects
    Accept ICMP redirect messages only for gateways, listed in
    default gateway list. Enabled by default.
 
+hidden
+   Hide addresses attached to this device from another devices.
+   Such addresses will never be selected by source address autoselection
+   mechanism, host does not answer broadcast ARP requests for them,
+   does not announce it as source address of ARP requests,     but they
+   are still reachable via IP. This flag is activated only if it is
+   enabled both in specific device section and in "all" section.
+
 shared_media
    If it is not set the kernel does not assume that different subnets
    on this device can communicate directly. Default setting is 'yes'.  
index edff4c1b483824b5b4195d81cca8ed3c1a0d4138..e9610c23e95c3558d1ea12760389c43c8307b22f 100644 (file)
@@ -2,10 +2,10 @@
 Documentation for the NeoMagic 256AV/256ZX sound driver
 =======================================================
 
-You're looking at version 1.0 of the driver.  (Woohoo!) It has been
+You're looking at version 1.11 of the driver.  (Woohoo!) It has been
 successfully tested against the following laptop models:
 
-       Sony Z505S/Z505SX/Z505DX
+       Sony Z505S/Z505SX/Z505DX/Z505RX
        Sony F150, F160, F180, F250, F270, F280, PCG-F26
        Dell Latitude CPi, CPt (various submodels)
 
@@ -16,9 +16,13 @@ This driver was developed without any support or assistance from
 NeoMagic.  There is no warranty, expressed, implied, or otherwise.  It
 is free software in the public domain; feel free to use it, sell it,
 give it to your best friends, even claim that you wrote it (but why?!)
-but don't come whining to me, NeoMagic, Sony, Dell, or anyone else
+but don't go whining to me, NeoMagic, Sony, Dell, or anyone else
 when it blows up your computer.
 
+Version 1.11 fixes a bug uncovered by Timidity--the sound would start clicking
+after the first MIDI file was finished playing.  There are no other changes
+over 1.1.
+
 ============
 Installation
 ============
@@ -42,16 +46,19 @@ hurting themselves.  It works correctly if it shares an IRQ with
 another device (it normally shares IRQ 9 with the builtin eepro100
 ethernet on the Sony Z505 laptops). 
 
-It does not run the card in any sort of compatibility mode. Thus it
-almost certainly will not work on laptops that have the
-SB16-compatible codec/mixer; you will want to use the standard SB16
-OSS driver with these chipsets.  I cannot provide any assistance with
-machines using the SB-16 compatible version.
+It does not run the card in any sort of compatibility mode. It will
+not work on laptops that have the SB16-compatible, AD1848-compatible
+or CS4232-compatible codec/mixer; you will want to use the appropriate
+compatible OSS driver with these chipsets.  I cannot provide any
+assistance with machines using the SB16, AD1848 or CS4232 compatible
+versions.  (The driver now attempts to detect the mixer version, and
+will refuse to load if it believes the hardware is not not
+AC97-compatible.)
 
 The sound support is very basic, but it does include simultaneous
 playback and record capability.  The mixer support is also quite
 simple, although this is in keeping with the rather limited
-functionality of the chipset.  
+functionality of the chipset.
 
 There is no hardware synthesizer available, as the Losedows OPL-3 and
 MIDI support is done via hardware emulation.
@@ -63,8 +70,6 @@ models of laptops.)  The Z505 series does not have a builtin CD-ROM,
 so of course the CD-ROM input doesn't work.  It does work on laptops
 with a builtin CD-ROM drive.
 
-Recording is mono 8-bit only.
-
 The mixer device does not appear to have any tone controls, at least
 on the Z505 series.  The mixer module checks for tone controls in the
 AC97 mixer, and will enable them if they are available.
@@ -93,10 +98,11 @@ Known problems
     limitation.  It may be possible to support other speeds in the future.
 
   * There is no support for the telephone mixer/codec.  There is support
-    for a phonein/phoneout device if your mixer program supports it;
-    whether or not it does anything is anyone's guess.  (Reports on this
-    would be appreciated.)
-  
+    for a phonein/phoneout device in the mixer driver;  whether or not 
+    it does anything is anyone's guess.  (Reports on this would be
+    appreciated.  You'll have to figure out how to get the phone to
+    go off-hook before it'll work, tho.)
+
   * This driver was not written with any cooperation or support from
     NeoMagic.  If you have any questions about this, see their website
     for their official stance on supporting open source drivers.
@@ -118,8 +124,8 @@ This implies a few things:
 
   * Sometimes the NM256 driver has to guess at where the buffer 
     should be placed, especially if the module is loaded after the
-    X server is started.  It's usually correct, but it will fail on
-    the Sony F250.
+    X server is started.  It's usually correct, but it will consistently
+    fail on the Sony F250.
 
   * Virtual screens greater than 1024x768x16 under XFree86 are
     problematic on laptops with only 2.5MB of screen RAM. This
@@ -139,10 +145,16 @@ screen), the best fix is to
 On the F250, it is possible to force the driver to load properly even
 after the XFree86 server is started by doing:
 
-       insmod nm256.o buffertop=0x25a800
+       insmod nm256 buffertop=0x25a800
 
 This forces the audio buffers to the correct offset in screen RAM.
 
+One user has reported a similar problem on the Sony F270, although
+others apparently aren't seeing any problems.  His suggested command
+is
+
+       insmod nm256 buffertop=0x272800
+
 =================
 Official WWW site
 =================
@@ -154,6 +166,17 @@ The official site for the NM256 driver is:
 You should always be able to get the latest version of the driver there,
 and the driver will be supported for the foreseeable future.
 
+==============
+Z505RX and IDE
+==============
+
+There appears to be a problem with the IDE chipset on the Z505RX; one
+of the symptoms is that sound playback periodically hangs (when the
+disk is accessed).  The user reporting the problem also reported that
+enabling all of the IDE chipset workarounds in the kernel solved the
+problem, tho obviously only one of them should be needed--if someone
+can give me more details I would appreciate it.
+
 ==============================
 Z505S/Z505SX on-board Ethernet
 ==============================
@@ -176,11 +199,30 @@ PCMCIA and the Z505S/Z505SX/Z505DX
 ==================================
 
 There is also a known problem with the Sony Z505S and Z505SX hanging
-if a PCMCIA card is inserted while the ethernet driver is loaded.
-This is caused by tons of spurious IRQ 9s, probably generated from the
-PCMCIA or ACPI bridges.  There is currently no fix for the problem,
-and the only known workaround is to disable the ethernet interface
-before inserting or removing a PCMCIA card.
+if a PCMCIA card is inserted while the ethernet driver is loaded, or
+in some cases if the laptop is suspended.  This is caused by tons of
+spurious IRQ 9s, probably generated from the PCMCIA or ACPI bridges.
+
+There is currently no fix for the problem that works in every case.
+The only known workarounds are to disable the ethernet interface
+before inserting or removing a PCMCIA card, or with some cards
+disabling the PCMCIA card before ejecting it will also help the
+problem with the laptop hanging when the card is ejected.
+
+One user has reported that setting the tcic's cs_irq to some value
+other than 9 (like 11) fixed the problem.  This doesn't work on my
+Z505S, however--changing the value causes the cardmgr to stop seeing
+card insertions and removals, cards don't seem to work correctly, and
+I still get hangs if a card is inserted when the kernel is booted.
+
+Using the latest ethernet driver and pcmcia package allows me to
+insert an Adaptec 1480A SlimScsi card without the laptop hanging,
+although I still have to shut down the card before ejecting or
+powering down the laptop.  However, similar experiments with a DE-660
+ethernet card still result in hangs when the card is inserted.  I am
+beginning to think that the interrupts are CardBus-related, since the
+Adaptec card is a CardBus card, and the DE-660 is not; however, I
+don't have any other CardBus cards to test with.
 
 ======
 Thanks
@@ -208,6 +250,11 @@ I will be rather unfair and single out a few people, however:
        Jeff Garzik, for various helpful suggestions on the AC97
        interface
 
+       "Mr. Bumpy" for feedback on the Z505RX
+
+       Bill Nottingham, for generous assistance in getting the mixer ID
+       code working
+
 =================
 Previous versions
 =================
@@ -227,3 +274,11 @@ mixer module.
 
 Version 0.75 renamed all the functions and files with slightly more
 generic names.
+
+Version 1.1 contains a change to try and detect non-AC97 versions of
+the hardware, and not install itself appropriately.  It should also
+reinitialize the hardware on an APM resume event, assuming that APM
+was configured into your kernel.
+
+Note that previous versions of this document claimed that recording was
+8-bit only; it actually has been working for 16-bits all along.
index 1b617feacffaebc96e1a9e4a4fdcdb0ea345b326..13c39ff6fd1a8e9a03cc10ad9561d55638eea02a 100644 (file)
@@ -811,8 +811,10 @@ M: kgb@manjak.knm.org.pl
 S:     Maintained
 
 TLAN NETWORK DRIVER
+P:     Torben Mathiasen
+M:     torben.mathiasen@compaq.com
 L:     tlan@vuser.vu.union.edu
-S:     Orphan
+S:     Maintained
 
 TOKEN-RING NETWORK DRIVER
 P:     Paul Norton
index 5528f2421ffe6da625a4c92712e6c4000148090c..605340612d0a7a2e99c4483f4821e06b0f5ff554 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 14
-EXTRAVERSION = pre12
+EXTRAVERSION = pre13
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
index 334dbfb56cfc36094d3aef01d5d89d95186d7ddd..606fe1e5a9208d40ad2cafaecab4791598bec069 100644 (file)
@@ -211,7 +211,11 @@ paging_init(unsigned long start_mem, unsigned long end_mem)
                if (cluster->usage & 3)
                        continue;
                pfn = cluster->start_pfn;
+               if (pfn >= MAP_NR(end_mem)) /* if we overrode mem size */
+                       continue;
                nr = cluster->numpages;
+               if ((pfn + nr) > MAP_NR(end_mem)) /* if override in cluster */
+                       nr = MAP_NR(end_mem) - pfn;
 
                while (nr--)
                        clear_bit(PG_reserved, &mem_map[pfn++].flags);
@@ -221,7 +225,7 @@ paging_init(unsigned long start_mem, unsigned long end_mem)
           the last slot of the L1 page table.  */
        memset((void *) ZERO_PAGE(0), 0, PAGE_SIZE);
        memset(swapper_pg_dir, 0, PAGE_SIZE);
-       newptbr = ((unsigned long) swapper_pg_dir - PAGE_OFFSET) >> PAGE_SHIFT;
+       newptbr = MAP_NR(swapper_pg_dir);
        pgd_val(swapper_pg_dir[1023]) =
                (newptbr << 32) | pgprot_val(PAGE_KERNEL);
 
@@ -328,8 +332,8 @@ mem_init(unsigned long start_mem, unsigned long end_mem)
                kill_page(tmp);
                free_page(tmp);
        }
-       tmp = nr_free_pages << PAGE_SHIFT;
-       printk("Memory: %luk available\n", tmp >> 10);
+       tmp = nr_free_pages << (PAGE_SHIFT - 10);
+       printk("Memory: %luk available\n", tmp);
        return;
 }
 
@@ -358,7 +362,7 @@ si_meminfo(struct sysinfo *val)
        i = max_mapnr;
        val->totalram = 0;
        val->sharedram = 0;
-       val->freeram = nr_free_pages << PAGE_SHIFT;
+       val->freeram = ((unsigned long)nr_free_pages) << PAGE_SHIFT;
        val->bufferram = buffermem;
        while (i-- > 0)  {
                if (PageReserved(mem_map+i))
index 3a52d51138a750a70f63c5069d1ac96f5da9a0e2..4526add030689fe938d8f9081df115707e86b27a 100644 (file)
@@ -114,7 +114,6 @@ volatile unsigned long smp_invalidate_needed;               /* Used for the invalidate map th
 volatile unsigned long kstack_ptr;                     /* Stack vector for booting CPUs                        */
 struct cpuinfo_x86 cpu_data[NR_CPUS];                  /* Per CPU bogomips and other parameters                */
 static unsigned int num_processors = 1;                        /* Internal processor count                             */
-unsigned long mp_ioapic_addr = 0xFEC00000;             /* Address of the I/O apic (not yet used)               */
 unsigned char boot_cpu_id = 0;                         /* Processor that is doing the boot up                  */
 static int smp_activated = 0;                          /* Tripped once we need to start cross invalidating     */
 int apic_version[NR_CPUS];                             /* APIC version number                                  */
@@ -493,6 +492,8 @@ static int __init smp_scan_config(unsigned long base, unsigned long length)
                                        cpu_present_map=3;
                                        num_processors=2;
                                        printk("I/O APIC at 0xFEC00000.\n");
+                                       mp_apics[0].mpc_apicaddr = 0xFEC00000;
+                                       mp_apic_entries = 1;
 
                                        /*
                                         * Save the default type number, we
index 34b6fe51ab7e48ed6b835f1208a28958405a3930..6a4309f86270f8df2f5e30a9fdcc78c2e9ede0cc 100644 (file)
@@ -227,7 +227,10 @@ int ide_multwrite (ide_drive_t *drive, unsigned int mcount)
 #endif
                spin_lock_irqsave(&io_request_lock, flags);     /* Is this really necessary? */
                if ((rq->nr_sectors -= nsect) <= 0)
+               {
+                       spin_unlock_irqrestore(&io_request_lock, flags);
                        break;
+               }
                if ((rq->current_nr_sectors -= nsect) == 0) {
                        if ((rq->bh = rq->bh->b_reqnext) != NULL) {
                                rq->current_nr_sectors = rq->bh->b_size>>9;
index c94c9b3c6e76333f775b2eb8b5fb68d524601371..a404fcab33b730a8cb9934a68899d3c6b84804a2 100644 (file)
@@ -315,7 +315,7 @@ static int create_missing_block(struct loop_device *lo, int block, int blksize)
                /* Do what the default llseek() code would have done */
                file->f_pos = new_offset;
                file->f_reada = 0;
-               file->f_version = ++event;
+               file->f_version = ++global_event;
        }
 
        if (file->f_op->write == NULL) {
index 4b2281efa30f77799884c1a19ba9329dcdc7a971..d76947188c9cf2f3f3e6053dd24c2c0c15959db5 100644 (file)
@@ -32,6 +32,8 @@
  *     Alan Cox        <alan@redhat.com>:      Fixed the out of memory
  *                                             handling.
  *
+ *     Torben Mathiasen <torben.mathiasen@compaq.com> New Maintainer!
+ *
  ********************************************************************/
 
 
index fa1f91bbee143a71957214190421273157cc9b16..3c135e7471c20a42fcb7cabd4a5a49580f35d764 100644 (file)
@@ -14,6 +14,8 @@
  *
  ** This file is best viewed/edited with tabstop=4, colums>=132
  *
+ *  Dec 10, 1999       Torben Mathiasen <torben.mathiasen@compaq.com>
+ *                     New Maintainer
  ********************************************************************/
 
 
index 63468443a9630e89656284e8b369f3e0a8683af0..c710f4cc600d7aa756fb9e6cfc7c37540e1661f8 100644 (file)
  * along with this kernel; if not, write to the Free Software           *
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
  *                                                                      *
- * Tested with Linux 1.2.13, ..., 2.2.                                *
+ * Tested with Linux 1.2.13, ..., 2.2.12                                *
  *                                                                      *
  * $Log: gdth.c,v $
+ * Revision 1.30  1999/11/02 13:42:39  achim
+ * ARRAY_DRV_LIST2 implemented
+ * Now 255 log. and 100 host drives supported
+ *
+ * Revision 1.29  1999/10/05 13:28:47  achim
+ * GDT_CLUST_RESET added
+ *
+ * Revision 1.28  1999/08/12 13:44:54  achim
+ * MOUNTALL removed
+ * Cluster drives -> removeable drives
+ *
+ * Revision 1.27  1999/06/22 07:22:38  achim
+ * Small changes
+ *
+ * Revision 1.26  1999/06/10 16:09:12  achim
+ * Cluster Host Drive support: Bugfixes
+ *
+ * Revision 1.25  1999/06/01 16:03:56  achim
+ * gdth_init_pci(): Manipulate config. space to start RP controller
+ *
+ * Revision 1.24  1999/05/26 11:53:06  achim
+ * Cluster Host Drive support added
+ *
  * Revision 1.23  1999/03/26 09:12:31  achim
  * Default value for hdr_channel set to 0
  *
  * Initial revision
  *
  ************************************************************************/
-#ident "$Id: gdth.c,v 1.23 1999/03/26 09:12:31 achim Exp $" 
+#ident "$Id: gdth.c,v 1.30 1999/11/02 13:42:39 achim Exp $" 
 
 /* All GDT Disk Array Controllers are fully supported by this driver.
  * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
@@ -581,18 +604,18 @@ static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs)
 {
     *cyls = size /HEADS/SECS;
     if (*cyls <= MAXCYLS) {
-       *heads = HEADS;
-       *secs = SECS;
-    } else {                                           /* too high for 64*32 */
-       *cyls = size /MEDHEADS/MEDSECS;
-       if (*cyls <= MAXCYLS) {
-           *heads = MEDHEADS;
-           *secs = MEDSECS;
-       } else {                                        /* too high for 127*63 */
-           *cyls = size /BIGHEADS/BIGSECS;
-           *heads = BIGHEADS;
-           *secs = BIGSECS;
-       }
+        *heads = HEADS;
+        *secs = SECS;
+    } else {                                        /* too high for 64*32 */
+        *cyls = size /MEDHEADS/MEDSECS;
+        if (*cyls <= MAXCYLS) {
+            *heads = MEDHEADS;
+            *secs = MEDSECS;
+        } else {                                    /* too high for 127*63 */
+            *cyls = size /BIGHEADS/BIGSECS;
+            *heads = BIGHEADS;
+            *secs = BIGSECS;
+        }
     }
 }
 
@@ -686,7 +709,7 @@ __initfunc (static int gdth_search_pci(gdth_pci_str *pcistr))
             }
             TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%x\n",
                     pcistr[cnt].bus, PCI_SLOT(pcistr[cnt].device_fn), 
-                    pcistr[cnt].irq, pcistr[cnt].dpmem));
+                    pcistr[cnt].irq, (int)pcistr[cnt].dpmem));
             cnt++;
         }       
 #else   
@@ -981,7 +1004,11 @@ __initfunc (static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha))
     register gdt6m_dpram_str *dp6m_ptr;
     ulong32 retries;
     unchar prot_ver;
+    ushort command;
     int i, found = FALSE;
+#if LINUX_VERSION_CODE < 0x2015C
+    int rom_addr;
+#endif
 
     TRACE(("gdth_init_pci()\n"));
 
@@ -1137,6 +1164,36 @@ __initfunc (static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha))
             return 0;
         }
 
+        /* manipulate config. space to enable DPMEM, start RP controller */
+#if LINUX_VERSION_CODE >= 0x2015C
+        pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command);
+        command |= 6;
+        pci_write_config_word(pcistr->pdev, PCI_COMMAND, command);
+        if (pcistr->pdev->rom_address == 1UL)
+            pcistr->pdev->rom_address = 0UL;
+        i = 0xFEFF0001UL;
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, i);
+        gdth_delay(1);
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS,
+                               pcistr->pdev->rom_address);
+#else
+        pcibios_read_config_word(pcistr->bus, pcistr->device_fn,
+                                 PCI_COMMAND, &command);
+        command |= 6;
+        pcibios_write_config_word(pcistr->bus, pcistr->device_fn, 
+                                  PCI_COMMAND, command);
+        pcibios_read_config_dword(pcistr->bus, pcistr->device_fn,
+                                  PCI_ROM_ADDRESS, &rom_addr);
+        if (rom_addr == 1UL)
+            rom_addr = 0UL;
+        i = 0xFEFF0001UL;
+        pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+                                   PCI_ROM_ADDRESS, i);
+        gdth_delay(1);
+        pcibios_write_config_dword(pcistr->bus, pcistr->device_fn,
+                                   PCI_ROM_ADDRESS, rom_addr);
+#endif
+       
         /* check and reset interface area */
         dp6m_ptr = (gdt6m_dpram_str *)ha->brd;
         gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
@@ -1585,7 +1642,8 @@ __initfunc (static int gdth_search_drives(int hanum))
     gdth_drlist_str *drl;
     gdth_iochan_str *ioc;
     gdth_raw_iochan_str *iocr;
-    gdth_arraylist_str *alst;
+    gdth_arcdl_str *alst;
+    gdth_alist_str *alst2;
         
     TRACE(("gdth_search_drives() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
@@ -1607,19 +1665,6 @@ __initfunc (static int gdth_search_drives(int hanum))
     TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
     cdev_cnt = (ushort)ha->info;
 
-    /* mount all cache devices */
-    gdth_internal_cmd(hanum,CACHESERVICE,GDT_MOUNT,0xffff,1,0);
-    TRACE2(("gdth_search_drives(): mountall CACHESERVICE OK\n"));
-
-    /* initialize cache service after mountall */
-    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0)) {
-        printk("GDT: Initialization error cache service (code %d)\n",
-               ha->status);
-        return 0;
-    }
-    TRACE2(("gdth_search_drives() CACHES. init. after mountall\n"));
-    cdev_cnt = (ushort)ha->info;
-
     /* detect number of buses - try new IOCTL */
     iocr = (gdth_raw_iochan_str *)ha->pscratch;
     iocr->hdr.version        = 0xffffffff;
@@ -1747,22 +1792,37 @@ __initfunc (static int gdth_search_drives(int hanum))
                                   INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) {
                 for (j = 0; j < drv_cnt; ++j) {
                     drv_no = ((ulong32 *)ha->pscratch)[j];
-                    if (drv_no < MAX_HDRIVES) {
+                    if (drv_no < MAX_LDRIVES) {
                         ha->hdr[drv_no].is_logdrv = TRUE;
                         TRACE2(("Drive %d is log. drive\n",drv_no));
                     }
                 }
             }
+           alst = (gdth_arcdl_str *)ha->pscratch;
+           alst->entries_avail = MAX_LDRIVES;
+           alst->first_entry = 0;
+           alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]);
             if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
-                                  ARRAY_DRV_LIST | LA_CTRL_PATTERN,
-                                  0, 35 * sizeof(gdth_arraylist_str))) {
+                                  ARRAY_DRV_LIST2 | LA_CTRL_PATTERN, 
+                                  INVALID_CHANNEL, sizeof(gdth_arcdl_str) +
+                                 (alst->entries_avail-1) * sizeof(gdth_alist_str))) { 
+                for (j = 0; j < alst->entries_init; ++j) {
+                    ha->hdr[j].is_arraydrv = alst->list[j].is_arrayd;
+                    ha->hdr[j].is_master = alst->list[j].is_master;
+                    ha->hdr[j].is_parity = alst->list[j].is_parity;
+                    ha->hdr[j].is_hotfix = alst->list[j].is_hotfix;
+                    ha->hdr[j].master_no = alst->list[j].cd_handle;
+                }
+           } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                                        ARRAY_DRV_LIST | LA_CTRL_PATTERN,
+                                        0, 35 * sizeof(gdth_alist_str))) {
                 for (j = 0; j < 35; ++j) {
-                    alst = &((gdth_arraylist_str *)ha->pscratch)[j];
-                    ha->hdr[j].is_arraydrv = alst->is_arrayd;
-                    ha->hdr[j].is_master = alst->is_master;
-                    ha->hdr[j].is_parity = alst->is_parity;
-                    ha->hdr[j].is_hotfix = alst->is_hotfix;
-                    ha->hdr[j].master_no = alst->cd_handle;
+                    alst2 = &((gdth_alist_str *)ha->pscratch)[j];
+                    ha->hdr[j].is_arraydrv = alst2->is_arrayd;
+                    ha->hdr[j].is_master = alst2->is_master;
+                    ha->hdr[j].is_parity = alst2->is_parity;
+                    ha->hdr[j].is_hotfix = alst2->is_hotfix;
+                    ha->hdr[j].master_no = alst2->cd_handle;
                 }
             }
         }
@@ -1825,17 +1885,13 @@ __initfunc (static int gdth_search_drives(int hanum))
     for (i=0; i<cdev_cnt && i<MAX_HDRIVES; ++i) {
         TRACE(("gdth_search_drives() cachedev. %d\n",i));
         if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,i,0,0)) {
-            /* static relation between host drive number and Bus/ID */
-            TRACE(("gdth_search_dr() drive %d mapped to bus/id %d/%d\n",
-                   i,ha->bus_cnt,i));
-
             ha->hdr[i].present = TRUE;
             ha->hdr[i].size = ha->info;
 
             /* evaluate mapping (sectors per head, heads per cylinder) */
             ha->hdr[i].size &= ~SECS32;
             if (ha->info2 == 0) {
-               gdth_eval_mapping(ha->hdr[i].size,&drv_cyls,&drv_hds,&drv_secs);
+                gdth_eval_mapping(ha->hdr[i].size,&drv_cyls,&drv_hds,&drv_secs);
             } else {
                 drv_hds = ha->info2 & 0xff;
                 drv_secs = (ha->info2 >> 8) & 0xff;
@@ -1851,10 +1907,30 @@ __initfunc (static int gdth_search_drives(int hanum))
             /* get informations about device */
             if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,i,
                                   0,0)) {
-                TRACE(("gdth_search_dr() cache drive %d devtype %d\n",
+                TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
                        i,ha->info));
                 ha->hdr[i].devtype = (ushort)ha->info;
             }
+
+            /* cluster info */
+            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,i,
+                                  0,0)) {
+                TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
+                       i,ha->info));
+                ha->hdr[i].cluster_type = (unchar)ha->info;
+            } else {
+                ha->hdr[i].cluster_type = 0;
+            }           
+
+            /* R/W attributes */
+            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,i,
+                                  0,0)) {
+                TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
+                       i,ha->info));
+                ha->hdr[i].rw_attribs = (unchar)ha->info;
+            } else {
+                ha->hdr[i].rw_attribs = 0;
+            }           
         }
     }
 
@@ -1969,11 +2045,11 @@ static void gdth_next(int hanum)
         }
 
 #if LINUX_VERSION_CODE >= 0x010300
-        if (nscp->done != gdth_scsi_done) 
+        if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff
 #endif
         {
         if (nscp->SCp.phase == -1) {
-            nscp->SCp.phase = SCSIRAWSERVICE;           /* default: raw svc. */ 
+            nscp->SCp.phase = CACHESERVICE;           /* default: cache svc. */ 
             if (nscp->cmnd[0] == TEST_UNIT_READY) {
                 TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", 
                         b, t, nscp->lun));
@@ -1987,7 +2063,8 @@ static void gdth_next(int hanum)
                     if (b == 0 && ((t == 0 && nscp->lun == 1) ||
                          (t == 1 && nscp->lun == 0))) {
                         nscp->SCp.Status = GDT_SCAN_START;
-                        nscp->SCp.phase |= ((ha->scan_mode & 0x10 ? 1:0) << 8);
+                        nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) 
+                            | SCSIRAWSERVICE;
                         ha->scan_mode = 0x12;
                         TRACE2(("Scan mode: 0x%x (SCAN_START)\n", 
                                 ha->scan_mode));
@@ -1997,6 +2074,7 @@ static void gdth_next(int hanum)
                     }                   
                 } else if (ha->scan_mode == 0x12) {
                     if (b == ha->bus_cnt && t == ha->tid_cnt-1) {
+                        nscp->SCp.phase = SCSIRAWSERVICE;
                         nscp->SCp.Status = GDT_SCAN_END;
                         ha->scan_mode &= 0x10;
                         TRACE2(("Scan mode: 0x%x (SCAN_END)\n", 
@@ -2004,19 +2082,55 @@ static void gdth_next(int hanum)
                     }
                 }
             }
+            if (b == ha->virt_bus && nscp->cmnd[0] != INQUIRY &&
+                nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE &&
+                (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) {
+                if (!(ha->hdr[t].cluster_type & CLUSTER_MOUNTED)) {
+                    /* cluster drive NOT MOUNTED */
+                    if (!(ha->hdr[t].cluster_type & CLUSTER_RESERVED)) {
+                        /* cluster drive NOT RESERVED */
+                        nscp->SCp.Status = GDT_MOUNT;
+                    } else {
+                        /* cluster drive RESERVED (on the other node) */
+                        nscp->SCp.Status = GDT_CLUST_INFO;
+                    }
+                } else {
+                    if (!(ha->hdr[t].cluster_type & CLUSTER_RESERVED)) {
+                        /* cluster drive MOUNTED and not RESERVED */
+                        nscp->SCp.Status = GDT_CLUST_INFO;
+                    }
+                }
+            }
         }
         }
 
         if (nscp->SCp.Status != -1) {
-            if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) {
+            if ((nscp->SCp.phase & 0xff) == CACHESERVICE) {
+                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                    this_cmd = FALSE;
+                next_cmd = FALSE;
+            } else if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) {
                 if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b))))
                     this_cmd = FALSE;
                 next_cmd = FALSE;
+            } else {
+                memset((char*)nscp->sense_buffer,0,16);
+                nscp->sense_buffer[0] = 0x70;
+                nscp->sense_buffer[2] = NOT_READY;
+                nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                if (!nscp->SCp.have_data_in)
+                    nscp->SCp.have_data_in++;
+                else {
+                    GDTH_UNLOCK_HA(ha,flags);
+                    /* io_request_lock already active ! */
+                    nscp->scsi_done(nscp);
+                    GDTH_LOCK_HA(ha,flags);
+                }
             }
         } else
 
 #if LINUX_VERSION_CODE >= 0x010300
-        if (nscp->done == gdth_scsi_done) {
+        if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) {
             if (!(cmd_index=gdth_special_cmd(hanum,nscp)))
                 this_cmd = FALSE;
             next_cmd = FALSE;
@@ -2080,6 +2194,14 @@ static void gdth_next(int hanum)
                 }
                 break;
                 
+              case RESERVE:
+              case RELEASE:
+                TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ?
+                        "RESERVE" : "RELEASE"));
+                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                    this_cmd = FALSE;
+                break;
+                
               case READ_6:
               case WRITE_6:
               case READ_10:
@@ -2184,7 +2306,10 @@ static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
         inq.type_qual = (ha->hdr[t].devtype&4) ? TYPE_ROM:TYPE_DISK;
         /* you can here set all disks to removable, if you want to do
            a flush using the ALLOW_MEDIUM_REMOVAL command */
-        inq.modif_rmb = ha->hdr[t].devtype&1 ? 0x80:0x00;
+        inq.modif_rmb = 0x00;
+        if ((ha->hdr[t].devtype & 1) ||
+            (ha->hdr[t].cluster_type & CLUSTER_DRIVE))
+            inq.modif_rmb = 0x80;
         inq.version   = 2;
         inq.resp_aenc = 2;
         inq.add_length= 32;
@@ -2243,7 +2368,7 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
     register gdth_cmd_str *cmdp;
     struct scatterlist *sl;
     ushort i;
-    int cmd_index;
+    int cmd_index, read_write;
 
     ha = HADATA(gdth_ctr_tab[hanum]);
     cmdp = ha->pccb;
@@ -2265,31 +2390,38 @@ static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
         gdth_set_sema0(hanum);
 
     /* fill command */
-    if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
+    read_write = FALSE;
+    if (scp->SCp.Status != -1) 
+        cmdp->OpCode = scp->SCp.Status;         /* special cache cmd. */
+    else if (scp->cmnd[0] == RESERVE) 
+        cmdp->OpCode = GDT_RESERVE_DRV;
+    else if (scp->cmnd[0] == RELEASE)
+        cmdp->OpCode = GDT_RELEASE_DRV;
+    else if (scp->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
         if (scp->cmnd[4] & 1)                   /* prevent ? */
-            cmdp->OpCode      = GDT_MOUNT;
+            cmdp->OpCode = GDT_MOUNT;
         else if (scp->cmnd[3] & 1)              /* removable drive ? */
-            cmdp->OpCode      = GDT_UNMOUNT;
+            cmdp->OpCode = GDT_UNMOUNT;
+        else
+            cmdp->OpCode = GDT_FLUSH;
+    } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10) {
+        read_write = TRUE;
+        if (gdth_write_through || ((ha->hdr[hdrive].rw_attribs & 1) && 
+                                   (ha->cache_feat & GDT_WR_THROUGH)))
+            cmdp->OpCode = GDT_WRITE_THR;
         else
-            cmdp->OpCode      = GDT_FLUSH;
+            cmdp->OpCode = GDT_WRITE;
     } else {
-        if (scp->cmnd[0]==WRITE_6 || scp->cmnd[0]==WRITE_10) {
-            if (gdth_write_through)
-                cmdp->OpCode  = GDT_WRITE_THR;
-            else
-                cmdp->OpCode  = GDT_WRITE;
-        } else {
-            cmdp->OpCode      = GDT_READ;
-        }
+        read_write = TRUE;
+        cmdp->OpCode = GDT_READ;
     }
+    
+    cmdp->BoardNode        = LOCALBOARD;
+    cmdp->u.cache.DeviceNo = hdrive;
+    cmdp->u.cache.BlockNo  = 1;
+    cmdp->u.cache.sg_canz  = 0;
 
-    cmdp->BoardNode           = LOCALBOARD;
-    cmdp->u.cache.DeviceNo    = hdrive;
-
-    if (scp->cmnd[0]==ALLOW_MEDIUM_REMOVAL) {
-        cmdp->u.cache.BlockNo = 1;
-        cmdp->u.cache.sg_canz = 0;
-    } else {
+    if (read_write) {
         if (scp->cmd_len != 6) {
             cmdp->u.cache.BlockNo = ntohl(*(ulong32*)&scp->cmnd[2]);
             cmdp->u.cache.BlockCnt= (ulong32)ntohs(*(ushort*)&scp->cmnd[7]);
@@ -2942,37 +3074,92 @@ static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
         }
         /* cache or raw service */
         if (ha->status == S_OK) {
-            scp->SCp.Message = S_OK;
+            scp->SCp.Message = (int)(ha->info<<16|S_OK);
             if (scp->SCp.Status != -1) {
                 TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n",
                         scp->SCp.Status));
-                scp->SCp.Status = -1;
-                scp->SCp.this_residual = HIGH_PRI;
-                return 2;
+                /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */
+                if (scp->SCp.Status == GDT_CLUST_INFO) {
+                    ha->hdr[scp->target].cluster_type = (unchar)ha->info;
+                    if (!(ha->hdr[scp->target].cluster_type & 
+                        CLUSTER_MOUNTED)) {
+                        /* NOT MOUNTED -> MOUNT */
+                        if (!(ha->hdr[scp->target].cluster_type & 
+                            CLUSTER_RESERVED)) {
+                            /* cluster drive NOT RESERVED */
+                            scp->SCp.Status = GDT_MOUNT;
+                        } else {
+                            /* cluster drive RESERVED (on the other node) */
+                            scp->SCp.Status = GDT_MOUNT;
+                            scp->SCp.phase = -2;      /* reservation conflict */
+                        }
+                    } else {
+                        scp->SCp.Status = -1;
+                    }
+                    /* retry */
+                    scp->SCp.this_residual = HIGH_PRI;
+                    return 2;
+                } else if (scp->SCp.Status == GDT_MOUNT) {
+                    ha->hdr[scp->target].cluster_type |= CLUSTER_MOUNTED;
+                    scp->SCp.Status = -1;
+                    /* return UNIT_ATTENTION */
+                    memset((char*)scp->sense_buffer,0,16);
+                    scp->sense_buffer[0] = 0x70;
+                    scp->sense_buffer[2] = UNIT_ATTENTION;
+                    scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                } else {
+                    scp->SCp.Status = -1;
+                    /* retry */
+                    scp->SCp.this_residual = HIGH_PRI;
+                    return 2;
+                }
+            } else {
+                /* RESERVE/RELEASE ? */
+                if (scp->cmnd[0] == RESERVE) {
+                    ha->hdr[scp->target].cluster_type |= CLUSTER_RESERVED;
+                } else if (scp->cmnd[0] == RELEASE) {
+                    ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
+                }           
+                scp->result = DID_OK << 16;
             }
-            scp->result = DID_OK << 16;
         } else if (ha->status == S_BSY) {
             TRACE2(("Controller busy -> retry !\n"));
-            scp->SCp.Message = S_BSY;
+            scp->SCp.Message = (int)(ha->info<<16|S_BSY);
+            if (scp->SCp.Status == GDT_MOUNT)
+                scp->SCp.Status = GDT_CLUST_INFO;
+            /* retry */
             return 2;
         } else {
             scp->SCp.Message = (int)((ha->info<<16)|ha->status);
+            memset((char*)scp->sense_buffer,0,16);
+            scp->sense_buffer[0] = 0x70;
+            scp->sense_buffer[2] = NOT_READY;
+
             if (scp->SCp.Status != -1) {
                 TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n",
                         scp->SCp.Status, ha->status));
-                scp->SCp.Status = -1;
-                scp->SCp.this_residual = HIGH_PRI;
-                return 2;
-            }
-            if (service == CACHESERVICE) {
-                memset((char*)scp->sense_buffer,0,16);
-                scp->sense_buffer[0] = 0x70;
-                scp->sense_buffer[2] = NOT_READY;
+                if (scp->SCp.Status == GDT_SCAN_START ||
+                    scp->SCp.Status == GDT_SCAN_END) {
+                    scp->SCp.Status = -1;
+                    /* retry */
+                    scp->SCp.this_residual = HIGH_PRI;
+                    return 2;
+                }
+                scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+            } else if (scp->cmnd[0] == RESERVE ||
+                       scp->cmnd[0] == RELEASE) {
+                scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+            } else if (service == CACHESERVICE) {
+               if (ha->status == S_CACHE_UNKNOWN &&
+                   (ha->hdr[scp->target].cluster_type & 
+                    CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) {
+                   /* bus reset -> force GDT_CLUST_INFO */
+                   ha->hdr[scp->target].cluster_type &= ~CLUSTER_RESERVED;
+               }
                 scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
-
 #if LINUX_VERSION_CODE >= 0x010300
                 if (scp->done != gdth_scsi_done)
-#endif 
+#endif  
                 {
                     dvr.size = sizeof(dvr.eu.sync);
                     dvr.eu.sync.ionode  = hanum;
@@ -3754,24 +3941,46 @@ int gdth_eh_bus_reset(Scsi_Cmnd *scp)
     TRACE2(("gdth_eh_bus_reset()\n"));
     hanum = NUMDATA(scp->host)->hanum;
     ha    = HADATA(gdth_ctr_tab[hanum]);
-    if (scp->channel == ha->virt_bus)
-        return FAILED;
 
+    /* clear command tab */
     GDTH_LOCK_HA(ha, flags);
-    for (i = 0; i < MAXID; ++i)
-        ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[i] = 0;
     for (i = 0; i < GDTH_MAXCMDS; ++i) {
         cmnd = ha->cmd_tab[i].cmnd;
         if (!SPECIAL_SCP(cmnd) && cmnd->channel == scp->channel)
             ha->cmd_tab[i].cmnd = UNUSED_CMND;
     }
-    gdth_polling = TRUE;
-    while (gdth_test_busy(hanum))
-        gdth_delay(0);
-    gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
-                      BUS_L2P(ha,scp->channel), 0, 0);
-    gdth_polling = FALSE;
     GDTH_UNLOCK_HA(ha, flags);
+
+    if (scp->channel == ha->virt_bus) {
+        /* host drives */
+        for (i = 0; i < MAX_HDRIVES; ++i) {
+            if (ha->hdr[i].present && 
+                (ha->hdr[i].cluster_type & CLUSTER_RESERVED) 
+                == CLUSTER_RESERVED) { 
+                GDTH_LOCK_HA(ha, flags);
+                gdth_polling = TRUE;
+                while (gdth_test_busy(hanum))
+                    gdth_delay(0);
+                if (gdth_internal_cmd(hanum, CACHESERVICE, 
+                                      GDT_CLUST_RESET, i, 0, 0))
+                    ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED;
+                gdth_polling = FALSE;
+                GDTH_UNLOCK_HA(ha, flags);
+            }
+        }
+    } else {
+        /* raw devices */
+        GDTH_LOCK_HA(ha, flags);
+        for (i = 0; i < MAXID; ++i)
+            ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[i] = 0;
+        gdth_polling = TRUE;
+        while (gdth_test_busy(hanum))
+            gdth_delay(0);
+        gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
+                          BUS_L2P(ha,scp->channel), 0, 0);
+        gdth_polling = FALSE;
+        GDTH_UNLOCK_HA(ha, flags);
+    }
     return SUCCESS;
 }
 
@@ -3800,12 +4009,12 @@ int gdth_bios_param(Disk *disk,int dev,int *ip)
 
     if (disk->device->channel != ha->virt_bus || ha->hdr[t].heads == 0) {
         /* raw device or host drive without mapping information */
-       TRACE2(("Evaluate mapping\n"));
-       gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]);
+        TRACE2(("Evaluate mapping\n"));
+        gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]);
     } else {
-       ip[0] = ha->hdr[t].heads;
-       ip[1] = ha->hdr[t].secs;
-       ip[2] = disk->capacity / ip[0] / ip[1];
+        ip[0] = ha->hdr[t].heads;
+        ip[1] = ha->hdr[t].secs;
+        ip[2] = disk->capacity / ip[0] / ip[1];
     }
 
     TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n",
@@ -3869,18 +4078,16 @@ static void gdth_flush(int hanum)
     Scsi_Cmnd       scp;
     Scsi_Device     sdev;
     gdth_cmd_str    gdtcmd;
+    char            cmnd[12];   
 
     TRACE2(("gdth_flush() hanum %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = gdth_ctr_tab[hanum];
-    sdev.id = sdev.host->this_id;
-    scp.cmd_len = 12;
-    scp.host = gdth_ctr_tab[hanum];
-    scp.target = sdev.host->this_id;
+    memset(cmnd, 0xff, 12);
+    sdev.host = scp.host = gdth_ctr_tab[hanum];
+    sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
-    scp.use_sg = 0;
 
     for (i = 0; i < MAX_HDRIVES; ++i) {
         if (ha->hdr[i].present) {
@@ -3891,7 +4098,7 @@ static void gdth_flush(int hanum)
             gdtcmd.u.cache.BlockNo = 1;
             gdtcmd.u.cache.sg_canz = 0;
             TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
-            gdth_do_cmd(&scp, &gdtcmd, 30);
+            gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
         }
     }
 }
@@ -3908,10 +4115,11 @@ void gdth_halt(void)
     Scsi_Cmnd       scp;
     Scsi_Device     sdev;
     gdth_cmd_str    gdtcmd;
+    char            cmnd[12];
 #endif
 
 #if LINUX_VERSION_CODE >= 0x020100
-    TRACE2(("gdth_halt() event %d\n",event));
+    TRACE2(("gdth_halt() event %d\n",(int)event));
     if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
         return NOTIFY_DONE;
 #else
@@ -3930,19 +4138,16 @@ void gdth_halt(void)
         /* controller reset */
         memset(&sdev,0,sizeof(Scsi_Device));
         memset(&scp, 0,sizeof(Scsi_Cmnd));
-        sdev.host = gdth_ctr_tab[hanum];
-        sdev.id = sdev.host->this_id;
-        scp.cmd_len = 12;
-        scp.host = gdth_ctr_tab[hanum];
-        scp.target = sdev.host->this_id;
+        memset(cmnd, 0xff, 12);
+        sdev.host = scp.host = gdth_ctr_tab[hanum];
+        sdev.id = scp.target = sdev.host->this_id;
         scp.device = &sdev;
-        scp.use_sg = 0;
 
         gdtcmd.BoardNode = LOCALBOARD;
         gdtcmd.Service = CACHESERVICE;
         gdtcmd.OpCode = GDT_RESET;
         TRACE2(("gdth_halt(): reset controller %d\n", hanum));
-        gdth_do_cmd(&scp, &gdtcmd, 10);
+        gdth_do_cmd(&scp, &gdtcmd, cmnd, 10);
 #endif
     }
     printk("Done.\n");
index 6d77ef1ae9c7c2cfb00b084d4b9e1967674ae2fd..02aae111348c871bc1e09ad51f5c52ff01206dd1 100644 (file)
@@ -10,7 +10,7 @@
  *
  * <achim@vortex.de>
  *
- * $Id: gdth.h,v 1.21 1999/03/26 09:12:24 achim Exp $
+ * $Id: gdth.h,v 1.24 1999/11/02 13:43:49 achim Exp $
  */
 
 #include <linux/version.h>
@@ -29,9 +29,9 @@
 /* defines, macros */
 
 /* driver version */
-#define GDTH_VERSION_STR        "1.14"
+#define GDTH_VERSION_STR        "1.17"
 #define GDTH_VERSION            1
-#define GDTH_SUBVERSION         14
+#define GDTH_SUBVERSION         17
 
 /* protocol version */
 #define PROTOCOL_VERSION        1
 #define MAXID           127
 #define MAXLUN          8
 #define MAXBUS          6
-#define MAX_HDRIVES     35                      /* max. host drive count */
+#define MAX_HDRIVES     100                     /* max. host drive count */
+#define MAX_LDRIVES     255                     /* max. log. drive count */
 #define MAX_EVENTS      100                     /* event buffer count */
 #define MAX_RES_ARGS    40                      /* device reservation, 
                                                    must be a multiple of 4 */
 #define IC_QUEUE_BYTES  4
 #define DPMEM_COMMAND_OFFSET    IC_HEADER_BYTES+IC_QUEUE_BYTES*MAXOFFSETS
 
+/* cluster_type constants */
+#define CLUSTER_DRIVE         1
+#define CLUSTER_MOUNTED       2
+#define CLUSTER_RESERVED      4
+#define CLUSTER_RESERVE_STATE (CLUSTER_DRIVE|CLUSTER_MOUNTED|CLUSTER_RESERVED)
+
 /* cache/raw service commands */
 #define GDT_INIT        0                       /* service initialization */
 #define GDT_READ        1                       /* read command */
 #define GDT_READ_THR    17                      /* read through */
 #define GDT_EXT_INFO    18                      /* extended info */
 #define GDT_RESET       19                      /* controller reset */
+#define GDT_RESERVE_DRV 20                      /* reserve host drive */
+#define GDT_RELEASE_DRV 21                      /* release host drive */
+#define GDT_CLUST_INFO  22                      /* cluster info */
+#define GDT_RW_ATTRIBS  23                      /* R/W attribs (write thru,..)*/
+#define GDT_CLUST_RESET 24                      /* releases the cluster drives*/
 
 /* additional raw service commands */
 #define GDT_RESERVE     14                      /* reserve dev. to raw serv. */
 #define SCSI_DEF_CNT    0x15                    /* grown/primary defects */
 #define DSK_STATISTICS  0x4b                    /* SCSI disk statistics */
 #define IOCHAN_DESC     0x5d                    /* description of IO channel */
-#define IOCHAN_RAW_DESC 0x5e                    /* description of raw IO channel */
+#define IOCHAN_RAW_DESC 0x5e                    /* description of raw IO chn. */
 #define L_CTRL_PATTERN  0x20000000L             /* SCSI IOCTL mask */
 #define ARRAY_INFO      0x12                    /* array drive info */
 #define ARRAY_DRV_LIST  0x0f                    /* array drive list */
+#define ARRAY_DRV_LIST2 0x34                    /* array drive list (new) */
 #define LA_CTRL_PATTERN 0x10000000L             /* array IOCTL mask */
 #define CACHE_DRV_CNT   0x01                    /* cache drive count */
 #define CACHE_DRV_LIST  0x02                    /* cache drive list */
 /* service errors */
 #define S_OK            1                       /* no error */
 #define S_BSY           7                       /* controller busy */
+#define S_CACHE_UNKNOWN 12                      /* cache serv.: drive unknown */
 #define S_RAW_SCSI      12                      /* raw serv.: target error */
 #define S_RAW_ILL       0xff                    /* raw serv.: illegal */
 
@@ -300,7 +314,7 @@ typedef struct {
     unchar      revision[4];                    /* revision */
     ulong32     sy_rate;                        /* current rate for sync. tr. */
     ulong32     sy_max_rate;                    /* max. rate for sync. tr. */
-    ulong32     no_ldrive;                      /* belongs to this logical drv.*/
+    ulong32     no_ldrive;                      /* belongs to this log. drv.*/
     ulong32     blkcnt;                         /* number of blocks */
     ushort      blksize;                        /* size of block in bytes */
     unchar      available;                      /* flag: access is available */
@@ -455,7 +469,15 @@ typedef struct {
     unchar      is_parity;                      /* Flag: is parity drive? */
     unchar      is_hotfix;                      /* Flag: is hotfix drive? */
     unchar      res[3];
-} PACKED gdth_arraylist_str;
+} PACKED gdth_alist_str;
+
+typedef struct {
+    ulong32    entries_avail;                  /* allocated entries */
+    ulong32    entries_init;                   /* returned entries */
+    ulong32    first_entry;                    /* first entry number */
+    ulong32    list_offset;                    /* offset of following list */
+    gdth_alist_str list[1];                    /* list */
+} PACKED gdth_arcdl_str;
 
 /* cache info/config IOCTL */
 typedef struct {
@@ -864,13 +886,15 @@ typedef struct {
         ulong32         size;                   /* capacity */
         unchar          ldr_no;                 /* log. drive no. */
         unchar          rw_attribs;             /* r/w attributes */
+        unchar          cluster_type;           /* cluster properties */
+        unchar          reserved;
         ulong32         start_sec;              /* start sector */
-    } hdr[MAX_HDRIVES];                         /* host drives */
+    } hdr[MAX_LDRIVES];                         /* host drives */
     struct {
         unchar          lock;                   /* channel locked? (hot plug) */
         unchar          pdev_cnt;               /* physical device count */
         unchar          local_no;               /* local channel number */
-       unchar          io_cnt[MAXID];          /* current IO count */
+        unchar          io_cnt[MAXID];          /* current IO count */
         ulong32         address;                /* channel address */
         ulong32         id_list[MAXID];         /* IDs of the phys. devices */
     } raw[MAXBUS];                              /* SCSI channels */
index 68395616009dee6f2c57c03cdeb2543ed7eee3e6..64a00c5900ff1e54237a419b72f8f39797624843 100644 (file)
@@ -2,7 +2,7 @@
 #define _GDTH_IOCTL_H
 
 /* gdth_ioctl.h
- * $Id: gdth_ioctl.h,v 1.2 1998/12/17 15:42:49 achim Exp $
+ * $Id: gdth_ioctl.h,v 1.3 1999/05/26 11:49:57 achim Exp $
  */
 
 /* IOCTLs */
 #define GDTIOCTL_DRVERS     (GDTIOCTL_MASK | 1) /* get driver version */
 #define GDTIOCTL_CTRTYPE    (GDTIOCTL_MASK | 2) /* get controller type */
 #define GDTIOCTL_OSVERS     (GDTIOCTL_MASK | 3) /* get OS version */
+#define GDTIOCTL_HDRLIST    (GDTIOCTL_MASK | 4) /* get host drive list */
 #define GDTIOCTL_CTRCNT     (GDTIOCTL_MASK | 5) /* get controller count */
 #define GDTIOCTL_LOCKDRV    (GDTIOCTL_MASK | 6) /* lock host drive */
 #define GDTIOCTL_LOCKCHN    (GDTIOCTL_MASK | 7) /* lock channel */
 #define GDTIOCTL_EVENT      (GDTIOCTL_MASK | 8) /* read controller events */
+#define GDTIOCTL_SCSI       (GDTIOCTL_MASK | 9) /* SCSI command */
+#define GDTIOCTL_RESET_BUS  (GDTIOCTL_MASK |10) /* reset SCSI bus */
 
 #define GDTIOCTL_MAGIC      0xaffe0001UL
 
@@ -45,6 +48,13 @@ typedef struct {
             int             handle;
             unchar          evt[34];            /* event structure */
         } event;
+        struct {
+            unchar          bus;                /* SCSI bus */
+            unchar          target;             /* target ID */
+            unchar          lun;                /* LUN */
+            unchar          cmd_len;            /* command length */
+            unchar          cmd[12];            /* SCSI command */
+        } scsi;
     } iu;
 } gdth_iowr_str;
 
@@ -79,6 +89,12 @@ typedef struct {
             int             handle;
             unchar          evt[34];            /* event structure */
         } event;
+        struct {
+            unchar          bus;                /* SCSI bus, 0xff: invalid */
+            unchar          target;             /* target ID */
+            unchar          lun;                /* LUN */
+            unchar          cluster_type;       /* cluster properties */
+        } hdr_list[35];                         /* index is host drive number */
     } iu;
 } gdth_iord_str;
 
index a6c79e7df3d6c46b041b27decf7d96537bdffdf8..aa10802c48c373bea547b7c395c5b8312566b1be 100644 (file)
@@ -1,9 +1,8 @@
 /* gdth_proc.c 
- * $Id: gdth_proc.c,v 1.13 1999/03/22 16:12:53 achim Exp $
+ * $Id: gdth_proc.c,v 1.16 1999/11/02 13:44:11 achim Exp $
  */
 
 #include "gdth_ioctl.h"
-#include <linux/version.h>
 
 int gdth_proc_info(char *buffer,char **start,off_t offset,int length,   
                    int hostno,int inout)
@@ -41,13 +40,9 @@ static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum)
 
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = gdth_ctr_vtab[vh];
-    sdev.id = sdev.host->this_id;
-    scp.cmd_len = 12;
-    scp.host = gdth_ctr_vtab[vh];
-    scp.target = sdev.host->this_id;
+    sdev.host = scp.host = gdth_ctr_vtab[vh];
+    sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
-    scp.use_sg = 0;
 
     if (length >= 4) {
         if (strncmp(buffer,"gdth",4) == 0) {
@@ -73,6 +68,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
     gdth_ha_str     *ha;
     gdth_cmd_str    gdtcmd;
     gdth_cpar_str   *pcpar;
+    char            cmnd[12];
 
     TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
@@ -80,6 +76,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
     drive = -1;
     wb_mode = 0;
     found = FALSE;
+    memset(cmnd, 0xff, 12);
 
     if (length >= 5 && strncmp(buffer,"flush",5)==0) {
         buffer += 6;
@@ -106,7 +103,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
                 gdtcmd.u.cache.DeviceNo = i;
                 gdtcmd.u.cache.BlockNo = 1;
                 gdtcmd.u.cache.sg_canz = 0;
-                gdth_do_cmd(&scp, &gdtcmd, 30);
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
             }
         }
         if (!found)
@@ -159,7 +156,7 @@ static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
         gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
         gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
         pcpar->write_back = wb_mode==1 ? 0:1;
-        gdth_do_cmd(&scp, &gdtcmd, 30);
+        gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
         gdth_ioctl_free(hanum);
         printk("Done.\n");
         return(orig_length);
@@ -180,6 +177,8 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
     ulong32         *ppadd, add_size;
     ulong32         *ppadd2, add_size2;
     ulong           flags;
+    char            cmnd[12];   
+    gdth_cmd_str    gdtcmd;
 
     TRACE2(("gdth_set_bin_info() ha %d\n",hanum));
     ha = HADATA(gdth_ctr_tab[hanum]);
@@ -188,6 +187,7 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
     pcmd = NULL;
     ppadd = ppadd2 = NULL;
     add_size = add_size2 = 0;
+    memset(cmnd, 0xff, 12);
 
     if (length < GDTOFFSOF(gdth_iowr_str,iu))
         return(-EINVAL);
@@ -242,7 +242,7 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
             *ppadd2 = virt_to_bus(piord->iu.general.data+add_size);
         }
         /* do IOCTL */
-        gdth_do_cmd(&scp, pcmd, piowr->timeout);
+        gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
         piord->status = (ulong32)scp.SCp.Message;
         break;
 
@@ -363,10 +363,10 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
                 pevt->event_data.size = sizeof(pevt->event_data.eu.async);
                 gdth_log_event(&pevt->event_data, NULL);
             }
-           GDTH_LOCK_HA(ha, flags);
+            GDTH_LOCK_HA(ha, flags);
             gdth_store_event(ha, pevt->event_source, pevt->event_idx,
                              &pevt->event_data);
-           GDTH_UNLOCK_HA(ha, flags);
+            GDTH_UNLOCK_HA(ha, flags);
         } else if (piowr->iu.event.erase == 0xfe) {
             gdth_clear_events();
         } else if (piowr->iu.event.erase == 0) {
@@ -382,6 +382,58 @@ static int gdth_set_bin_info(char *buffer,int length,int hanum,Scsi_Cmnd scp)
         piord->status = S_OK;
         break;
 
+      case GDTIOCTL_SCSI:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        scp.target = scp.device->id = piowr->iu.scsi.target;
+        scp.channel = scp.device->channel = piowr->iu.scsi.bus;
+        memcpy(cmnd, piowr->iu.scsi.cmd, 12);
+        scp.cmd_len = piowr->iu.scsi.cmd_len;
+        gdth_do_cmd(&scp, pcmd, cmnd, piowr->timeout);
+        piord->status = (ulong32)scp.result;
+        break;
+
+      case GDTIOCTL_RESET_BUS:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        scp.channel = scp.device->channel = piowr->iu.scsi.bus;
+        piord->status = (ulong32)gdth_eh_bus_reset( &scp );
+        break;
+
+      case GDTIOCTL_HDRLIST:
+        if (!gdth_ioctl_alloc( hanum, sizeof(gdth_iord_str) ))
+            return(-EBUSY);
+        piord = (gdth_iord_str *)ha->pscratch;
+        piord->size = sizeof(gdth_iord_str);
+        piord->status = S_OK;
+        for (i = 0; i < MAX_HDRIVES; ++i) {
+            if (ha->hdr[i].present) {
+                piord->iu.hdr_list[i].bus = ha->virt_bus;
+                piord->iu.hdr_list[i].target = i;
+                piord->iu.hdr_list[i].lun = 0;
+                piord->iu.hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
+                if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) {
+                    gdtcmd.BoardNode = LOCALBOARD;
+                    gdtcmd.Service = CACHESERVICE;
+                    gdtcmd.OpCode = GDT_CLUST_INFO;
+                    gdtcmd.u.cache.DeviceNo = i;
+                    gdtcmd.u.cache.BlockNo = 0;
+                    gdtcmd.u.cache.sg_canz = 0;
+                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                    if ((scp.SCp.Message & 0xffff) == S_OK)
+                        piord->iu.hdr_list[i].cluster_type = 
+                            (unchar)(scp.SCp.Message>>16);
+               }
+            } else {
+                piord->iu.hdr_list[i].bus = 0xff;
+            }
+        }
+        break;
+
       default:
         return(-EINVAL);
     }
@@ -404,6 +456,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
     gdth_evt_str estr;
     Scsi_Cmnd scp;
     Scsi_Device sdev;
+    char cmnd[12];
     char hrec[161];
     struct timeval tv;
 
@@ -420,13 +473,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
 
     memset(&sdev,0,sizeof(Scsi_Device));
     memset(&scp, 0,sizeof(Scsi_Cmnd));
-    sdev.host = gdth_ctr_vtab[vh];
-    sdev.id = sdev.host->this_id;
-    scp.cmd_len = 12;
-    scp.host = gdth_ctr_vtab[vh];
-    scp.target = sdev.host->this_id;
+    memset(cmnd, 0xff, 12);
+    sdev.host = scp.host = gdth_ctr_vtab[vh];
+    sdev.id = scp.target = sdev.host->this_id;
     scp.device = &sdev;
-    scp.use_sg = 0;
 
     /* look for buffer ID in length */
     if (id > 1) {
@@ -514,7 +564,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
             /* 2. about physical devices */
             size = sprintf(buffer+len,"\nPhysical Devices:");
             len += size;  pos = begin + len;
-           flag = FALSE;
+            flag = FALSE;
             
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
@@ -536,8 +586,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                     sizeof(pds->list[0]);
                 if (pds->entries > cnt)
                     pds->entries = cnt;
-                gdth_do_cmd(&scp, &gdtcmd, 30);
-                if (scp.SCp.Message != S_OK) 
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                if ((scp.SCp.Message & 0xffff) != S_OK) 
                     pds->count = 0;
                 TRACE2(("pdr_statistics() entries %d status %d\n",
                         pds->count, scp.SCp.Message));
@@ -556,8 +606,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                     gdtcmd.u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
                     gdtcmd.u.ioctl.channel = 
                         ha->raw[i].address | ha->raw[i].id_list[j];
-                    gdth_do_cmd(&scp, &gdtcmd, 30);
-                    if (scp.SCp.Message == S_OK) {
+                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                    if ((scp.SCp.Message & 0xffff) == S_OK) {
                         strncpy(hrec,pdi->vendor,8);
                         strncpy(hrec+8,pdi->product,16);
                         strncpy(hrec+24,pdi->revision,4);
@@ -566,7 +616,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                                        "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
                                        'A'+i,pdi->target_id,pdi->lun,hrec);
                         len += size;  pos = begin + len;
-                       flag = TRUE;
+                        flag = TRUE;
                         pdi->no_ldrive &= 0xffff;
                         if (pdi->no_ldrive == 0xffff)
                             strcpy(hrec,"--");
@@ -607,8 +657,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                         gdtcmd.u.ioctl.channel = 
                             ha->raw[i].address | ha->raw[i].id_list[j];
                         pdef->sddc_type = 0x08;
-                        gdth_do_cmd(&scp, &gdtcmd, 30);
-                        if (scp.SCp.Message == S_OK) {
+                        gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                        if ((scp.SCp.Message & 0xffff) == S_OK) {
                             size = sprintf(buffer+len,
                                            " Grown Defects:\t%d\n",
                                            pdef->sddc_cnt);
@@ -619,10 +669,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
             }
             gdth_ioctl_free(hanum);
 
-           if (!flag) {
-               size = sprintf(buffer+len, "\n --\n");
-               len += size;  pos = begin + len;
-           }
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
+            }
             if (pos < offset) {
                 len = 0;
                 begin = pos;
@@ -633,11 +683,11 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
             /* 3. about logical drives */
             size = sprintf(buffer+len,"\nLogical Drives:");
             len += size;  pos = begin + len;
-           flag = FALSE;
+            flag = FALSE;
 
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
-            for (i = 0; i < MAX_HDRIVES; ++i) {
+            for (i = 0; i < MAX_LDRIVES; ++i) {
                 if (!ha->hdr[i].is_logdrv)
                     continue;
                 drv_no = i;
@@ -654,8 +704,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                     gdtcmd.u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
                     gdtcmd.u.ioctl.subfunc = CACHE_DRV_INFO;
                     gdtcmd.u.ioctl.channel = drv_no;
-                    gdth_do_cmd(&scp, &gdtcmd, 30);
-                    if (scp.SCp.Message != S_OK)
+                    gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                    if ((scp.SCp.Message & 0xffff) != S_OK)
                         break;
                     pcdi->ld_dtype >>= 16;
                     j++;
@@ -675,7 +725,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                                        "\n Number:       \t%-2d        \tStatus:        \t%s\n",
                                        drv_no, hrec);
                         len += size;  pos = begin + len;
-                       flag = TRUE;
+                        flag = TRUE;
                         no_mdrv = pcdi->cd_ldcnt;
                         if (no_mdrv > 1 || pcdi->ld_slave != -1) {
                             is_mirr = TRUE;
@@ -720,10 +770,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
             }       
             gdth_ioctl_free(hanum);
         
-           if (!flag) {
-               size = sprintf(buffer+len, "\n --\n");
-               len += size;  pos = begin + len;
-           }   
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
+            }   
             if (pos < offset) {
                 len = 0;
                 begin = pos;
@@ -734,11 +784,11 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
             /* 4. about array drives */
             size = sprintf(buffer+len,"\nArray Drives:");
             len += size;  pos = begin + len;
-           flag = FALSE;
+            flag = FALSE;
 
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
-            for (i = 0; i < MAX_HDRIVES; ++i) {
+            for (i = 0; i < MAX_LDRIVES; ++i) {
                 if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
                     continue;
                 /* 4.a array drive info */
@@ -751,8 +801,8 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                 gdtcmd.u.ioctl.param_size = sizeof(gdth_arrayinf_str);
                 gdtcmd.u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
                 gdtcmd.u.ioctl.channel = i;
-                gdth_do_cmd(&scp, &gdtcmd, 30);
-                if (scp.SCp.Message == S_OK) {
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                if ((scp.SCp.Message & 0xffff) == S_OK) {
                     if (pai->ai_state == 0)
                         strcpy(hrec, "idle");
                     else if (pai->ai_state == 2)
@@ -792,10 +842,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
             }
             gdth_ioctl_free(hanum);
         
-           if (!flag) {
-               size = sprintf(buffer+len, "\n --\n");
-               len += size;  pos = begin + len;
-           }
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
+            }
             if (pos < offset) {
                 len = 0;
                 begin = pos;
@@ -806,11 +856,11 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
             /* 5. about host drives */
             size = sprintf(buffer+len,"\nHost Drives:");
             len += size;  pos = begin + len;
-           flag = FALSE;
+            flag = FALSE;
 
             if (!gdth_ioctl_alloc(hanum, GDTH_SCRATCH))
                 goto stop_output;
-            for (i = 0; i < MAX_HDRIVES; ++i) {
+            for (i = 0; i < MAX_LDRIVES; ++i) {
                 if (!ha->hdr[i].is_logdrv || 
                     (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
                     continue;
@@ -826,15 +876,15 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                 gdtcmd.u.ioctl.channel = i;
                 phg->entries = MAX_HDRIVES;
                 phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
-                gdth_do_cmd(&scp, &gdtcmd, 30);
-                if (scp.SCp.Message != S_OK) {
+                gdth_do_cmd(&scp, &gdtcmd, cmnd, 30);
+                if ((scp.SCp.Message & 0xffff) != S_OK) {
                     ha->hdr[i].ldr_no = i;
                     ha->hdr[i].rw_attribs = 0;
                     ha->hdr[i].start_sec = 0;
                 } else {
                     for (j = 0; j < phg->entries; ++j) {
                         k = phg->entry[j].host_drive;
-                        if (k >= MAX_HDRIVES)
+                        if (k >= MAX_LDRIVES)
                             continue;
                         ha->hdr[k].ldr_no = phg->entry[j].log_drive;
                         ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
@@ -854,7 +904,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                                "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
                                i, ha->hdr[i].ldr_no);
                 len += size;  pos = begin + len;
-               flag = TRUE;
+                flag = TRUE;
 
                 size = sprintf(buffer+len,
                                " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
@@ -862,10 +912,10 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                 len += size;  pos = begin + len;
             }
         
-           if (!flag) {
-               size = sprintf(buffer+len, "\n --\n");
-               len += size;  pos = begin + len;
-           }
+            if (!flag) {
+                size = sprintf(buffer+len, "\n --\n");
+                len += size;  pos = begin + len;
+            }
             if (pos < offset) {
                 len = 0;
                 begin = pos;
@@ -887,7 +937,7 @@ static int gdth_get_info(char *buffer,char **start,off_t offset,
                 gdth_log_event(&estr.event_data, hrec);
                 do_gettimeofday(&tv);
                 sec = (int)(tv.tv_sec - estr.first_stamp);
-               if (sec < 0) sec = 0;
+                if (sec < 0) sec = 0;
                 size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
                                sec/3600, sec%3600/60, sec%60, hrec);
                 len += size;  pos = begin + len;
@@ -929,19 +979,24 @@ stop_output:
     return(len);
 }
 
-static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *gdtcmd,int timeout)
+static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, 
+                        char *cmnd, int timeout)
 {
-    char cmnd[12];
     struct semaphore sem = MUTEX_LOCKED;
+    unsigned bufflen;
 
     TRACE2(("gdth_do_cmd()\n"));
-    memset(cmnd, 0, 12);
+    if (gdtcmd != NULL) { 
+        scp->SCp.this_residual = IOCTL_PRI;
+        bufflen = sizeof(gdth_cmd_str);
+    } else {
+        scp->SCp.this_residual = DEFAULT_PRI;
+        bufflen = 0;
+    }
     scp->request.rq_status = RQ_SCSI_BUSY;
     scp->request.sem = &sem;
-    scp->SCp.this_residual = IOCTL_PRI;
     GDTH_LOCK_SCSI_DOCMD();
-    scsi_do_cmd(scp, cmnd, gdtcmd, sizeof(gdth_cmd_str), 
-                gdth_scsi_done, timeout*HZ, 1);
+    scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
     GDTH_UNLOCK_SCSI_DOCMD();
     down(&sem);
 }
index 1a6f2d164b78195eca7264cc34d3080527e6e13b..d559389b74273aad1e429d6ff1b9f6c799a0f637 100644 (file)
@@ -2,7 +2,7 @@
 #define _GDTH_PROC_H
 
 /* gdth_proc.h 
- * $Id: gdth_proc.h,v 1.6 1999/03/05 14:32:36 achim Exp $
+ * $Id: gdth_proc.h,v 1.7 1999/05/26 11:49:32 achim Exp $
  */
 
 static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum);
@@ -18,7 +18,8 @@ static void gdth_stop_timeout(int hanum, int busnum, int id);
 static void gdth_start_timeout(int hanum, int busnum, int id);
 static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout);
 
-static void gdth_do_cmd(Scsi_Cmnd *scp,gdth_cmd_str *cmd,int timeout);
+static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, 
+                        char *cmnd, int timeout);
 void gdth_scsi_done(Scsi_Cmnd *scp);
 
 #endif
index 7f91fa4bd8fbb532a6b17060664b7050c82e45a0..631fac4150503485e21215cfaf4a11e6c2368649 100644 (file)
@@ -758,7 +758,7 @@ int isp2x00_detect(Scsi_Host_Template * tmpt)
                        hostdata->control_block.firm_opts = 0x0108;
                        hostdata->control_block.max_frame_len = 2048;
                        hostdata->control_block.max_iocb = 256;
-                       hostdata->control_block.exec_throttle = 8;
+                       hostdata->control_block.exec_throttle = QLOGICFC_CMD_PER_LUN;
                        hostdata->control_block.retry_delay = 5;
                        hostdata->control_block.retry_cnt = 1;
                        hostdata->control_block.node_name[0] = 0x0020;
@@ -1287,8 +1287,9 @@ int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
                /* scsi.c expects sense info in a different buffer */
                cmd->dataseg[0].d_base = virt_to_bus_low32(Cmnd->sense_buffer);
 #if BITS_PER_LONG > 32
-               cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->request_buffer);
+               cmd->dataseg[0].d_base_hi = virt_to_bus_high32(Cmnd->sense_buffer);
 #endif
+               cmd->dataseg[0].d_count = sizeof(Cmnd->sense_buffer);
                cmd->segment_cnt = 1;
                cmd->control_flags = CFLAG_READ;
                break;
index bc313134fcad55d0b73e821a45e97275174867e1..b54e62f769547d04639a38c9e7c5fdbdc0dd8922 100644 (file)
@@ -5,6 +5,10 @@
 /* And for stereo. */
 #define ST 1
 
+/* Whether or not the bits in the channel are inverted. */
+#define INV 1
+#define NINV 0
+
 static struct ac97_chn_desc {
     int ac97_regnum;
     int oss_channel;
@@ -13,21 +17,22 @@ static struct ac97_chn_desc {
     int oss_mask;
     int recordNum;
     u16 regmask;
+    int is_inverted;
 } mixerRegs[] = {
-    { AC97_MASTER_VOL_STEREO, SOUND_MIXER_VOLUME,   0x3f, ST, SOUND_MASK_VOLUME,   5, 0x0000 },
-    { AC97_MASTER_VOL_MONO,   SOUND_MIXER_PHONEOUT, 0x3f, MO, SOUND_MASK_PHONEOUT, 6, 0x0000 },
-    { AC97_MASTER_TONE,       SOUND_MIXER_TREBLE,   0x0f, MO, SOUND_MASK_TREBLE,  -1, 0x00ff },
-    { AC97_MASTER_TONE,       SOUND_MIXER_BASS,     0x0f, MO, SOUND_MASK_BASS,    -1, 0xff00 },
-    { AC97_PCBEEP_VOL,        SOUND_MIXER_SPEAKER,  0x0f, MO, SOUND_MASK_SPEAKER, -1, 0x001e },
-    { AC97_PHONE_VOL,         SOUND_MIXER_PHONEIN,  0x1f, MO, SOUND_MASK_PHONEIN,  7, 0x0000 },
-    { AC97_MIC_VOL,           SOUND_MIXER_MIC,      0x1f, MO, SOUND_MASK_MIC,      0, 0x0000 },
-    { AC97_LINEIN_VOL,        SOUND_MIXER_LINE,     0x1f, ST, SOUND_MASK_LINE,     4, 0x0000 },
-    { AC97_CD_VOL,            SOUND_MIXER_CD,       0x1f, ST, SOUND_MASK_CD,       1, 0x0000 },
-    { AC97_VIDEO_VOL,         SOUND_MIXER_VIDEO,    0x1f, ST, SOUND_MASK_VIDEO,    2, 0x0000 },
-    { AC97_AUX_VOL,           SOUND_MIXER_LINE1,    0x1f, ST, SOUND_MASK_LINE1,           3, 0x0000 },
-    { AC97_PCMOUT_VOL,        SOUND_MIXER_PCM,      0x1f, ST, SOUND_MASK_PCM,     -1, 0x0000 },
-    { AC97_RECORD_GAIN,       SOUND_MIXER_IGAIN,    0x0f, ST, SOUND_MASK_IGAIN,   -1, 0x0000 },
-    { -1,   -1,                   0xff, 0, 0,                   -1, 0x0000 },
+    { AC97_MASTER_VOL_STEREO, SOUND_MIXER_VOLUME,   0x3f, ST, SOUND_MASK_VOLUME,   5, 0x0000, INV  },
+    { AC97_MASTER_VOL_MONO,   SOUND_MIXER_PHONEOUT, 0x3f, MO, SOUND_MASK_PHONEOUT, 6, 0x0000, INV  },
+    { AC97_MASTER_TONE,       SOUND_MIXER_TREBLE,   0x0f, MO, SOUND_MASK_TREBLE,  -1, 0x00ff, INV  },
+    { AC97_MASTER_TONE,       SOUND_MIXER_BASS,     0x0f, MO, SOUND_MASK_BASS,    -1, 0xff00, INV  },
+    { AC97_PCBEEP_VOL,        SOUND_MIXER_SPEAKER,  0x0f, MO, SOUND_MASK_SPEAKER, -1, 0x001e, INV  },
+    { AC97_PHONE_VOL,         SOUND_MIXER_PHONEIN,  0x1f, MO, SOUND_MASK_PHONEIN,  7, 0x0000, INV  },
+    { AC97_MIC_VOL,           SOUND_MIXER_MIC,      0x1f, MO, SOUND_MASK_MIC,      0, 0x0000, INV  },
+    { AC97_LINEIN_VOL,        SOUND_MIXER_LINE,     0x1f, ST, SOUND_MASK_LINE,     4, 0x0000, INV  },
+    { AC97_CD_VOL,            SOUND_MIXER_CD,       0x1f, ST, SOUND_MASK_CD,       1, 0x0000, INV  },
+    { AC97_VIDEO_VOL,         SOUND_MIXER_VIDEO,    0x1f, ST, SOUND_MASK_VIDEO,    2, 0x0000, INV  },
+    { AC97_AUX_VOL,           SOUND_MIXER_LINE1,    0x1f, ST, SOUND_MASK_LINE1,           3, 0x0000, INV  },
+    { AC97_PCMOUT_VOL,        SOUND_MIXER_PCM,      0x1f, ST, SOUND_MASK_PCM,     -1, 0x0000, INV  },
+    { AC97_RECORD_GAIN,       SOUND_MIXER_IGAIN,    0x0f, ST, SOUND_MASK_IGAIN,   -1, 0x0000, NINV },
+    { -1,                    -1,                   0xff, 0,  0,                  -1, 0x0000, 0    },
 };
 
 static struct ac97_chn_desc *
@@ -104,6 +109,25 @@ ac97_init (struct ac97_hwint *dev)
     return 0;
 }
 
+/* Reset the mixer to the currently saved settings.  */
+int
+ac97_reset (struct ac97_hwint *dev)
+{
+    int x;
+
+    if (dev->reset_device (dev))
+       return -1;
+
+    /* Now set the registers back to their last-written values. */
+    for (x = 0; mixerRegs[x].ac97_regnum != -1; x++) {
+       int regnum = mixerRegs[x].ac97_regnum;
+       int value = dev->last_written_mixer_values [regnum / 2];
+       if (value >= 0)
+           ac97_put_register (dev, regnum, value);
+    }
+    return 0;
+}
+
 /* Return the contents of register REG; use the cache if the value in it
    is valid.  Returns a negative error code on failure. */
 int
@@ -156,38 +180,45 @@ ac97_put_register (struct ac97_hwint *dev, u8 reg, u16 value)
    scaled value on success.  */
 
 static int
-ac97_scale_to_oss_val (int value, int maxval, int is_stereo)
+ac97_scale_to_oss_val (int value, int maxval, int is_stereo, int inv)
 {
     /* Muted?  */
     if (value & AC97_MUTE)
        return 0;
 
     if (is_stereo)
-       return (ac97_scale_to_oss_val (value & 255, maxval, 0) << 8)
-       | (ac97_scale_to_oss_val ((value >> 8) & 255, maxval, 0) << 0);
+       return (ac97_scale_to_oss_val (value & 255, maxval, 0, inv) << 8)
+       | (ac97_scale_to_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0);
     else {
        int i;
        
        /* Inverted. */
-       value = maxval - value;
+       if (inv)
+           value = maxval - value;
 
        i = (value * 100 + (maxval / 2)) / maxval;
        if (i > 100)
             i = 100;
+       if (i < 0)
+           i = 0;
        return i;
     }
 }
 
 static int
-ac97_scale_from_oss_val (int value, int maxval, int is_stereo)
+ac97_scale_from_oss_val (int value, int maxval, int is_stereo, int inv)
 {
     if (is_stereo)
-       return (ac97_scale_from_oss_val (value & 255, maxval, 0) << 8)
-       | (ac97_scale_from_oss_val ((value >> 8) & 255, maxval, 0) << 0);
+       return (ac97_scale_from_oss_val (value & 255, maxval, 0, inv) << 8)
+       | (ac97_scale_from_oss_val ((value >> 8) & 255, maxval, 0, inv) << 0);
     else {
-       int i = maxval - ((value & 255) * maxval + 50) / 100;
+       int i = ((value & 255) * maxval + 50) / 100;
+       if (inv)
+           i = maxval - i;
        if (i < 0)
            i = 0;
+       if (i > maxval)
+           i = maxval;
        return i;
     }
 }
@@ -204,7 +235,8 @@ ac97_set_mixer (struct ac97_hwint *dev, int oss_channel, u16 oss_value)
     if (! ac97_is_valid_channel (dev, channel))
        return -ENODEV;
     scaled_value = ac97_scale_from_oss_val (oss_value, channel->maxval,
-                                           channel->is_stereo);
+                                           channel->is_stereo, 
+                                           channel->is_inverted);
     if (scaled_value < 0)
        return scaled_value;
 
@@ -253,7 +285,8 @@ ac97_get_mixer_scaled (struct ac97_hwint *dev, int oss_channel)
            regval >>= 1;
     }
     return ac97_scale_to_oss_val (regval, channel->maxval,
-                                 channel->is_stereo);
+                                 channel->is_stereo, 
+                                 channel->is_inverted);
 }
 
 int
@@ -383,8 +416,9 @@ ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd, caddr_t arg)
                    else
                        ret = -EFAULT;
                }
-               if (ret >= 0) {
-                   if (dev->last_written_OSS_values[channel] == AC97_REGVAL_UNKNOWN)
+               if (ret >= 0 && (dir & _IOC_READ)) {
+                   if (dev->last_written_OSS_values[channel]
+                       == AC97_REGVAL_UNKNOWN)
                        dev->last_written_OSS_values[channel]
                            = ac97_get_mixer_scaled (dev, channel);
                    ret = dev->last_written_OSS_values[channel];
index 490d69f880733878d76ef4f922de2f48038827b9..e1898584a2341c16b3f97347ccd1adfe446047e3 100644 (file)
@@ -10,7 +10,7 @@
 #include "sound_config.h"
 #include "sound_calls.h"
 
-#define  AC97_RESET              0x0000      //  */
+#define  AC97_RESET              0x0000      //
 #define  AC97_MASTER_VOL_STEREO  0x0002      // Line Out
 #define  AC97_HEADPHONE_VOL      0x0004      // 
 #define  AC97_MASTER_VOL_MONO    0x0006      // TAD Output
 #define AC97_RESERVED_3A       0x003A  /* Reserved */
 /* range 0x3c-0x58 - MODEM */
 
+/* AC'97 2.0 */
+#define AC97_EXTENDED_ID       0x0028  /* Extended Audio ID */
+#define AC97_EXTENDED_STATUS   0x002A  /* Extended Audio Status */
+#define AC97_PCM_FRONT_DAC_RATE 0x002C  /* PCM Front DAC Rate */
+#define AC97_PCM_SURR_DAC_RATE  0x002E  /* PCM Surround DAC Rate */
+#define AC97_PCM_LFE_DAC_RATE   0x0030  /* PCM LFE DAC Rate */
+#define AC97_PCM_LR_DAC_RATE   0x0032  /* PCM LR DAC Rate */
+#define AC97_PCM_MIC_ADC_RATE   0x0034  /* PCM MIC ADC Rate */
+#define AC97_CENTER_LFE_MASTER  0x0036  /* Center + LFE Master Volume */
+#define AC97_SURROUND_MASTER    0x0038  /* Surround (Rear) Master Volume */
+#define AC97_RESERVED_3A       0x003A  /* Reserved */
+/* range 0x3c-0x58 - MODEM */
+
 /* registers 0x005a - 0x007a are vendor reserved */
 
 #define  AC97_VENDOR_ID1         0x007c
@@ -207,6 +220,10 @@ extern int ac97_get_mixer_scaled (struct ac97_hwint *dev, int oss_channel);
 /* Default ioctl. */
 extern int ac97_mixer_ioctl (struct ac97_hwint *dev, unsigned int cmd,
                             caddr_t arg);
+
+/* Do a complete reset on the AC97 mixer, restoring all mixer registers to
+   the current values.  Normally used after an APM resume event.  */
+extern int ac97_reset (struct ac97_hwint *dev);
 #endif
 \f
 /*
index 4cc720ab94f8aaf8a7d900d203a977cb83400616..e506ab2d7d00e915001aef12ed43921d952652e3 100644 (file)
@@ -3,10 +3,12 @@
 
 #include "ac97.h"
 
+/* The revisions that we currently handle.  */
 enum nm256rev {
     REV_NM256AV, REV_NM256ZX
 };
 
+/* Per-card structure. */
 struct nm256_info 
 {
     /* Magic number used to verify that this struct is valid. */
@@ -34,10 +36,12 @@ struct nm256_info
     /* The mixer device. */
     int mixer_oss_dev;
 
-    /* Can only be opened once for each operation.  These aren't set
-       until an actual I/O operation is performed; this allows one
-       device to be open for read/write without inhibiting I/O to
-       the other device.  */
+    /* 
+     * Can only be opened once for each operation.  These aren't set
+     * until an actual I/O operation is performed; this allows one
+     * device to be open for read/write without inhibiting I/O to
+     * the other device.
+     */
     int is_open_play;
     int is_open_record;
 
@@ -46,25 +50,42 @@ struct nm256_info
     /* Ditto for recording a sample. */
     int recording;
 
-    /* The two memory ports. */
-    char *ports[2];
-
-    /* Starting offset of the port1 area mapped into memory. */
-    u32 port1_start;
-    /* Ending offset. */
-    u32 port1_end;
-    /* The offset of the end of the actual buffer area.  */
-    u32 bufend;
+    /* The two memory ports.  */
+    struct nm256_ports {
+       /* Physical address of the port. */
+       u32 physaddr;
+       /* Our mapped-in pointer. */
+       char *ptr;
+       /* PTR's offset within the physical port.  */
+       u32 start_offset;
+       /* And the offset of the end of the buffer.  */
+       u32 end_offset;
+    } port[2];
 
     /* The following are offsets within memory port 1. */
     u32 coeffBuf;
     u32 allCoeffBuf;
+
     /* Record and playback buffers. */
     u32 abuf1, abuf2;
 
     /* Offset of the AC97 mixer in memory port 2. */
     u32 mixer;
 
+    /* Offset of the mixer status register in memory port 2.  */
+    u32 mixer_status_offset;
+
+    /* Non-zero if we have written initial values to the mixer. */
+    u8 mixer_values_init;
+
+    u16 playRingsize;
+
+    /* 
+     * Status mask bit; (*mixer_status_loc & mixer_status_mask) == 0 means
+     * it's ready.  
+     */
+    u16 mixer_status_mask;
+
     /* The sizes of the playback and record ring buffers. */
     u32 playbackBufferSize;
     u32 recordBufferSize;
@@ -77,7 +98,7 @@ struct nm256_info
     /* The start of the block currently playing. */
     u32 curPlayPos;
 
-    /* The amount of data we requested to record. */
+    /* The amount of data we were requested to record. */
     u32 requestedRecAmt;
     /* The offset of the currently-recording block. */
     u32 curRecPos;
@@ -107,10 +128,17 @@ struct nm256_info
 /* Debug flag--bigger numbers mean more output. */
 extern int nm256_debug;
 
-/* Size of the second memory port. */
+/* The BIOS signature. */
+#define NM_SIGNATURE 0x4e4d0000
+/* Signature mask. */
+#define NM_SIG_MASK 0xffff0000
+
+/* Size of the second memory area. */
 #define NM_PORT2_SIZE 4096
-/* The location of the mixer. */
-#define NM_MIXER_BASE 0x600
+
+/* The base offset of the mixer in the second memory area. */
+#define NM_MIXER_OFFSET 0x600
+
 /* The maximum size of a coefficient entry. */
 #define NM_MAX_COEFFICIENT 0x5000
 
@@ -123,21 +151,33 @@ extern int nm256_debug;
 #define NM_MISC_INT_2 0x1
 #define NM_ACK_INT(CARD, X) nm256_writePort16((CARD), 2, NM_INT_REG, (X) << 1)
 
-/* For the second revision.  It uses the same interrupt register, but it
-   holds 32 bits instead of 16.  */
+/* The AV's "mixer ready" status bit and location. */
+#define NM_MIXER_STATUS_OFFSET 0xa04
+#define NM_MIXER_READY_MASK 0x0800
+#define NM_MIXER_PRESENCE 0xa06
+#define NM_PRESENCE_MASK 0x0050
+#define NM_PRESENCE_VALUE 0x0040
+
+/*
+ * For the ZX.  It uses the same interrupt register, but it holds 32
+ * bits instead of 16.
+ */
 #define NM2_PLAYBACK_INT 0x10000
 #define NM2_RECORD_INT 0x80000
 #define NM2_MISC_INT_1 0x8
 #define NM2_MISC_INT_2 0x2
 #define NM2_ACK_INT(CARD, X) nm256_writePort32((CARD), 2, NM_INT_REG, (X))
 
+/* The ZX's "mixer ready" status bit and location. */
+#define NM2_MIXER_STATUS_OFFSET 0xa06
+#define NM2_MIXER_READY_MASK 0x0800
+
 /* The playback registers start from here. */
 #define NM_PLAYBACK_REG_OFFSET 0x0
 /* The record registers start from here. */
 #define NM_RECORD_REG_OFFSET 0x200
 
-/* The rate register is located 2 bytes from the start of the register
-   area. */
+/* The rate register is located 2 bytes from the start of the register area. */
 #define NM_RATE_REG_OFFSET 2
 
 /* Mono/stereo flag, number of bits on playback, and rate mask. */
@@ -156,7 +196,7 @@ extern int nm256_debug;
 #define NM_AUDIO_MUTE_LEFT 0x8000
 #define NM_AUDIO_MUTE_RIGHT 0x0080
 
-/* Recording enable register */
+/* Recording enable register. */
 #define NM_RECORD_ENABLE_REG (NM_RECORD_REG_OFFSET + 0)
 #define NM_RECORD_ENABLE_FLAG 1
 #define NM_RECORD_FREERUN 2
@@ -179,26 +219,25 @@ extern int nm256_debug;
   if (port < 1 || port > 2 || card == NULL) \
       return -1; \
 \
-  if (port == 1) { \
-        if (offset < card->port1_start || offset >= card->port1_end) { \
-           printk (KERN_ERR "Bad port request port 1:0x%x\n", offset); \
-            return -1; \
-        } \
-        offset -= card->port1_start; \
-   } else if (offset < 0 || offset > 4096) { \
-        printk (KERN_ERR "Bad port request port 2: 0x%x\n", offset); \
-        return -1; \
-   }
+    if (offset < card->port[port - 1].start_offset \
+       || offset >= card->port[port - 1].end_offset) { \
+       printk (KERN_ERR "Bad access: port %d, offset 0x%x\n", port, offset); \
+       return -1; \
+    } \
+    offset -= card->port[port - 1].start_offset;
 
 #define DEFwritePortX(X, func) \
 static inline int nm256_writePort##X (struct nm256_info *card,\
-                                       int port, int offset, int value)\
+                                     int port, int offset, int value)\
 {\
     u##X *addr;\
+\
+    if (nm256_debug > 1)\
+        printk (KERN_DEBUG "Writing 0x%x to %d:0x%x\n", value, port, offset);\
 \
     NM_FIX_PORT;\
 \
-    addr = (u##X *)(card->ports[port - 1] + offset);\
+    addr = (u##X *)(card->port[port - 1].ptr + offset);\
     func (value, addr);\
     return 0;\
 }
@@ -207,29 +246,28 @@ DEFwritePortX (8, writeb)
 DEFwritePortX (16, writew)
 DEFwritePortX (32, writel)
 
-#define DEFreadPortX(X) \
+#define DEFreadPortX(X, func) \
 static inline u##X nm256_readPort##X (struct nm256_info *card,\
                                        int port, int offset)\
 {\
-    u##X *addr, res;\
+    u##X *addr;\
 \
     NM_FIX_PORT\
 \
-    addr = (u##X *)(card->ports[port - 1] + offset);\
-    memcpy_fromio (&res, addr, sizeof (res));\
-    return res;\
+    addr = (u##X *)(card->port[port - 1].ptr + offset);\
+    return func(addr);\
 }
 
-DEFreadPortX (8)
-DEFreadPortX (16)
-DEFreadPortX (32)
+DEFreadPortX (8, readb)
+DEFreadPortX (16, readw)
+DEFreadPortX (32, readl)
 
 static inline int
 nm256_writeBuffer8 (struct nm256_info *card, u8 *src, int port, int offset,
                      int amt)
 {
     NM_FIX_PORT;
-    memcpy_toio (card->ports[port - 1] + offset, src, amt);
+    memcpy_toio (card->port[port - 1].ptr + offset, src, amt);
     return 0;
 }
 
@@ -238,7 +276,7 @@ nm256_readBuffer8 (struct nm256_info *card, u8 *dst, int port, int offset,
                     int amt)
 {
     NM_FIX_PORT;
-    memcpy_fromio (dst, card->ports[port - 1] + offset, amt);
+    memcpy_fromio (dst, card->port[port - 1].ptr + offset, amt);
     return 0;
 }
 
index 387c44416da9c8ee1b3ee45e81ec13affd06599f..2c2e76f1d03cd8c8c27a06faa4095bac91926968 100644 (file)
@@ -1,20 +1,23 @@
-/* Audio driver for the NeoMagic 256AV and 256ZX chipsets in native
-   mode, with AC97 mixer support.
-
-   Overall design and parts of this code stolen from vidc_*.c and
-   skeleton.c.
-
-   Yeah, there are a lot of magic constants in here.  You tell ME what
-   they are.  I just get this stuff psychically, remember? 
-
-   This driver was written by someone who wishes to remain anonymous. 
-   It is in the public domain, so share and enjoy.  Try to make a profit
-   off of it; go on, I dare you.  */
-
+/* 
+ * Audio driver for the NeoMagic 256AV and 256ZX chipsets in native
+ * mode, with AC97 mixer support.
+ *
+ * Overall design and parts of this code stolen from vidc_*.c and
+ * skeleton.c.
+ *
+ * Yeah, there are a lot of magic constants in here.  You tell ME what
+ * they are.  I just get this stuff psychically, remember? 
+ *
+ * This driver was written by someone who wishes to remain anonymous. 
+ * It is in the public domain, so share and enjoy.  Try to make a profit
+ * off of it; go on, I dare you.  
+ */
+  
 #include <linux/config.h>
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/delay.h>
+#include <linux/apm_bios.h>
 
 #include "sound_config.h"
 #include "soundmodule.h"
 #include "nm256_coeff.h"
 
 int nm256_debug = 0;
+static int force_load = 0;
 
-/* The size of the playback reserve. */
+/* 
+ * The size of the playback reserve.  When the playback buffer has less
+ * than NM256_PLAY_WMARK_SIZE bytes to output, we request a new
+ * buffer.
+ */
 #define NM256_PLAY_WMARK_SIZE 512
 
 static struct audio_driver nm256_audio_driver;
@@ -31,16 +39,74 @@ static struct audio_driver nm256_audio_driver;
 static int nm256_grabInterrupt (struct nm256_info *card);
 static int nm256_releaseInterrupt (struct nm256_info *card);
 static void nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy);
-static void nm256_interrupt_zx (int irq, void *dev_id, 
-                                 struct pt_regs *dummy);
+static void nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy);
 
 /* These belong in linux/pci.h. */
 #define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005
 #define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006
 
+/* eeeew. */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,0)
+#define RSRCADDRESS(dev,num) ((dev)->resource[(num)].start)
+#else
+#define RSRCADDRESS(dev,num) ((dev)->base_address[(num)] \
+                             & PCI_BASE_ADDRESS_MEM_MASK)
+
+#endif
+
 /* List of cards.  */
 static struct nm256_info *nmcard_list;
 
+/* Release the mapped-in memory for CARD.  */
+static void
+nm256_release_ports (struct nm256_info *card)
+{
+    int x;
+
+    for (x = 0; x < 2; x++) {
+       if (card->port[x].ptr != NULL) {
+           u32 size = 
+               card->port[x].end_offset - card->port[x].start_offset;
+           release_region ((unsigned long) card->port[x].ptr, size);
+           card->port[x].ptr = NULL;
+       }
+    }
+}
+
+/* 
+ * Map in the memory ports for CARD, if they aren't already mapped in
+ * and have been configured.  If successful, a zero value is returned;
+ * otherwise any previously mapped-in areas are released and a non-zero
+ * value is returned.
+ *
+ * This is invoked twice, once for each port.  Ideally it would only be
+ * called once, but we now need to map in the second port in order to
+ * check how much memory the card has on the 256ZX.
+ */
+static int
+nm256_remap_ports (struct nm256_info *card)
+{
+    int x;
+
+    for (x = 0; x < 2; x++) {
+       if (card->port[x].ptr == NULL && card->port[x].end_offset > 0) {
+           u32 physaddr 
+               = card->port[x].physaddr + card->port[x].start_offset;
+           u32 size 
+               = card->port[x].end_offset - card->port[x].start_offset;
+
+           card->port[x].ptr = ioremap_nocache (physaddr, size);
+                                                 
+           if (card->port[x].ptr == NULL) {
+               printk (KERN_ERR "NM256: Unable to remap port %d\n", x + 1);
+               nm256_release_ports (card);
+               return -1;
+           }
+       }
+    }
+    return 0;
+}
+
 /* Locate the card in our list. */
 static struct nm256_info *
 nm256_find_card (int dev)
@@ -54,8 +120,10 @@ nm256_find_card (int dev)
     return NULL;
 }
 
-/* Ditto, but find the card struct corresponding to the mixer device DEV 
-   instead. */
+/*
+ * Ditto, but find the card struct corresponding to the mixer device DEV 
+ * instead. 
+ */
 static struct nm256_info *
 nm256_find_card_for_mixer (int dev)
 {
@@ -83,11 +151,13 @@ static int samplerates[9] = {
     8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000, 99999999
 };
 
-/* Set the card samplerate, word size and stereo mode to correspond to
-   the settings in the CARD struct for the specified device in DEV.
-   We keep two separate sets of information, one for each device; the
-   hardware is not actually configured until a read or write is
-   attempted. */
+/*
+ * Set the card samplerate, word size and stereo mode to correspond to
+ * the settings in the CARD struct for the specified device in DEV.
+ * We keep two separate sets of information, one for each device; the
+ * hardware is not actually configured until a read or write is
+ * attempted.
+ */
 
 int
 nm256_setInfo (int dev, struct nm256_info *card)
@@ -115,24 +185,33 @@ nm256_setInfo (int dev, struct nm256_info *card)
            break;
 
     if (x < 8) {
-       u8 speedbits = ((x << 4) & NM_RATE_MASK)
-           | (card->sinfo[w].bits == 16 ? NM_RATE_BITS_16: 0) 
-           | (card->sinfo[w].stereo ? NM_RATE_STEREO : 0);
+       u8 ratebits = ((x << 4) & NM_RATE_MASK);
+       if (card->sinfo[w].bits == 16)
+           ratebits |= NM_RATE_BITS_16;
+       if (card->sinfo[w].stereo)
+           ratebits |= NM_RATE_STEREO;
 
        card->sinfo[w].samplerate = samplerates[x];
 
+
        if (card->dev_for_play == dev && card->playing) {
+           if (nm256_debug)
+               printk (KERN_DEBUG "Setting play ratebits to 0x%x\n",
+                       ratebits);
            nm256_loadCoefficient (card, 0, x);
            nm256_writePort8 (card, 2,
-                               NM_PLAYBACK_REG_OFFSET + NM_RATE_REG_OFFSET,
-                               speedbits);
+                             NM_PLAYBACK_REG_OFFSET + NM_RATE_REG_OFFSET,
+                             ratebits);
        }
 
        if (card->dev_for_record == dev && card->recording) {
+           if (nm256_debug)
+               printk (KERN_DEBUG "Setting record ratebits to 0x%x\n",
+                       ratebits);
            nm256_loadCoefficient (card, 1, x);
-           nm256_writePort8 (card, 2, 
-                               NM_RECORD_REG_OFFSET + NM_RATE_REG_OFFSET,
-                               speedbits);
+           nm256_writePort8 (card, 2,
+                             NM_RECORD_REG_OFFSET + NM_RATE_REG_OFFSET,
+                             ratebits);
        }
        return 0;
     }
@@ -151,7 +230,7 @@ startPlay (struct nm256_info *card)
 
            /* Enable playback engine and interrupts. */
            nm256_writePort8 (card, 2, NM_PLAYBACK_ENABLE_REG,
-                               NM_PLAYBACK_ENABLE_FLAG | NM_PLAYBACK_FREERUN);
+                             NM_PLAYBACK_ENABLE_FLAG | NM_PLAYBACK_FREERUN);
 
            /* Enable both channels. */
            nm256_writePort16 (card, 2, NM_AUDIO_MUTE_REG, 0x0);
@@ -159,9 +238,11 @@ startPlay (struct nm256_info *card)
     }
 }
 
-/* Request one chunk of AMT bytes from the recording device.  When the
-   operation is complete, the data will be copied into BUFFER and the
-   function DMAbuf_inputintr will be invoked. */
+/* 
+ * Request one chunk of AMT bytes from the recording device.  When the
+ * operation is complete, the data will be copied into BUFFER and the
+ * function DMAbuf_inputintr will be invoked.
+ */
 
 static void
 nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt)
@@ -169,11 +250,14 @@ nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt)
     u32 endpos;
     int enableEngine = 0;
     u32 ringsize = card->recordBufferSize;
+    unsigned long flags;
 
     if (amt > (ringsize / 2)) {
-       /* Of course this won't actually work right, because the
-          caller is going to assume we will give what we got asked
-          for. */
+       /*
+        * Of course this won't actually work right, because the
+        * caller is going to assume we will give what we got asked
+        * for.
+        */
        printk (KERN_ERR "NM256: Read request too large: %d\n", amt);
        amt = ringsize / 2;
     }
@@ -183,8 +267,12 @@ nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt)
        return;
     }
 
-    /* If we're not currently recording, set up the start and end registers
-       for the recording engine. */
+    save_flags (flags);
+    cli ();
+    /*
+     * If we're not currently recording, set up the start and end registers
+     * for the recording engine.
+     */
     if (! card->recording) {
        card->recording = 1;
        if (nm256_grabInterrupt (card) == 0) {
@@ -200,10 +288,16 @@ nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt)
        }
        else {
            /* Not sure what else to do here.  */
+           restore_flags (flags);
            return;
        }
     }
 
+    /* 
+     * If we happen to go past the end of the buffer a bit (due to a
+     * delayed interrupt) it's OK.  So might as well set the watermark
+     * right at the end of the data we want.
+     */
     endpos = card->abuf2 + ((card->curRecPos + amt) % ringsize);
 
     card->recBuf = buffer;
@@ -213,6 +307,8 @@ nm256_startRecording (struct nm256_info *card, char *buffer, u32 amt)
     if (enableEngine)
        nm256_writePort8 (card, 2, NM_RECORD_ENABLE_REG,
                            NM_RECORD_ENABLE_FLAG | NM_RECORD_FREERUN);
+
+    restore_flags (flags);
 }
 
 /* Stop the play engine. */
@@ -221,7 +317,7 @@ stopPlay (struct nm256_info *card)
 {
     /* Shut off sound from both channels. */
     nm256_writePort16 (card, 2, NM_AUDIO_MUTE_REG,
-                        NM_AUDIO_MUTE_LEFT | NM_AUDIO_MUTE_RIGHT);
+                      NM_AUDIO_MUTE_LEFT | NM_AUDIO_MUTE_RIGHT);
     /* Disable play engine. */
     nm256_writePort8 (card, 2, NM_PLAYBACK_ENABLE_REG, 0);
     if (card->playing) {
@@ -248,18 +344,22 @@ stopRecord (struct nm256_info *card)
     }
 }
 
-/* Ring buffers, man.  That's where the hip-hop, wild-n-wooly action's at.
-   1972?
-
-   Write AMT bytes of BUFFER to the playback ring buffer, and start the
-   playback engine running.  It will only accept up to 1/2 of the total
-   size of the ring buffer.  */
+/*
+ * Ring buffers, man.  That's where the hip-hop, wild-n-wooly action's at.
+ * 1972?  (Well, I suppose it was cheep-n-easy to implement.)
+ *
+ * Write AMT bytes of BUFFER to the playback ring buffer, and start the
+ * playback engine running.  It will only accept up to 1/2 of the total
+ * size of the ring buffer.  No check is made that we're about to overwrite
+ * the currently-playing sample.
+ */
 
 static void
 nm256_write_block (struct nm256_info *card, char *buffer, u32 amt)
 {
     u32 ringsize = card->playbackBufferSize;
     u32 endstop;
+    unsigned long flags;
 
     if (amt > (ringsize / 2)) {
        printk (KERN_ERR "NM256: Write request too large: %d\n", amt);
@@ -275,48 +375,58 @@ nm256_write_block (struct nm256_info *card, char *buffer, u32 amt)
 
     card->requested_amt = amt;
 
+    save_flags (flags);
+    cli ();
+
     if ((card->curPlayPos + amt) >= ringsize) {
        u32 rem = ringsize - card->curPlayPos;
 
        nm256_writeBuffer8 (card, buffer, 1,
-                             card->abuf1 + card->curPlayPos,
-                             rem);
+                           card->abuf1 + card->curPlayPos,
+                           rem);
        if (amt > rem)
-           nm256_writeBuffer8 (card, buffer, 1, card->abuf1,
-                                 amt - rem);
+           nm256_writeBuffer8 (card, buffer + rem, 1, card->abuf1,
+                               amt - rem);
     } 
     else
        nm256_writeBuffer8 (card, buffer, 1,
                              card->abuf1 + card->curPlayPos,
                              amt);
 
-    /* Setup the start-n-stop-n-limit registers, and start that engine
-       goin'. 
-
-       Normally we just let it wrap around to avoid the click-click
-       action scene. */
+    /*
+     * Setup the start-n-stop-n-limit registers, and start that engine
+     * goin'. 
+     *
+     * Normally we just let it wrap around to avoid the click-click
+     * action scene.
+     */
     if (! card->playing) {
-       /* The PBUFFER_END register in this case points to one "word"
+       /* The PBUFFER_END register in this case points to one sample
           before the end of the buffer. */
        int w = (card->dev_for_play == card->dev[0] ? 0 : 1);
-       int wordsize = (card->sinfo[w].bits == 16 ? 2 : 1)
-           * (card->sinfo[w].stereo ? 2 : 1);
+       int sampsize = (card->sinfo[w].bits == 16 ? 2 : 1);
+
+       if (card->sinfo[w].stereo)
+           sampsize *= 2;
 
        /* Need to set the not-normally-changing-registers up. */
        nm256_writePort32 (card, 2, NM_PBUFFER_START,
                             card->abuf1 + card->curPlayPos);
        nm256_writePort32 (card, 2, NM_PBUFFER_END,
-                            card->abuf1 + ringsize - wordsize);
+                            card->abuf1 + ringsize - sampsize);
        nm256_writePort32 (card, 2, NM_PBUFFER_CURRP,
                             card->abuf1 + card->curPlayPos);
     }
     endstop = (card->curPlayPos + amt - NM256_PLAY_WMARK_SIZE) % ringsize;
     nm256_writePort32 (card, 2, NM_PBUFFER_WMARK, card->abuf1 + endstop);
+
     if (! card->playing)
        startPlay (card);
+
+    restore_flags (flags);
 }
 
-/* We just got a card playback interrupt; process it. */
+/*  We just got a card playback interrupt; process it.  */
 static void
 nm256_get_new_block (struct nm256_info *card)
 {
@@ -334,13 +444,14 @@ nm256_get_new_block (struct nm256_info *card)
        amt -= card->curPlayPos;
 
     if (card->requested_amt > (amt + NM256_PLAY_WMARK_SIZE)) {
-       u32 endstop = 
+       u32 endstop =
            card->curPlayPos + card->requested_amt - NM256_PLAY_WMARK_SIZE;
        nm256_writePort32 (card, 2, NM_PBUFFER_WMARK, card->abuf1 + endstop);
-    } else {
+    } 
+    else {
        card->curPlayPos += card->requested_amt;
        /* Get a new block to write.  This will eventually invoke
-          nm256_write_block ().  */
+          nm256_write_block () or stopPlay ().  */
        DMAbuf_outputintr (card->dev_for_play, 1);
     }
 }
@@ -348,9 +459,11 @@ nm256_get_new_block (struct nm256_info *card)
 /* Ultra cheez-whiz.  But I'm too lazy to grep headers. */
 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
 
-/* Read the last-recorded block from the ring buffer, copy it into the
-   saved buffer pointer, and invoke DMAuf_inputintr() with the recording
-   device. */
+/* 
+ * Read the last-recorded block from the ring buffer, copy it into the
+ * saved buffer pointer, and invoke DMAuf_inputintr() with the recording
+ * device. 
+ */
 
 static void
 nm256_read_block (struct nm256_info *card)
@@ -365,8 +478,10 @@ nm256_read_block (struct nm256_info *card)
         currptr = 0;
     }
 
-    /* This test is probably redundant; we shouldn't be here unless
-       it's true.  */
+    /*
+     * This test is probably redundant; we shouldn't be here unless
+     * it's true.
+     */
     if (card->recording) {
        /* If we wrapped around, copy everything from the start of our
           recording buffer to the end of the buffer. */
@@ -396,52 +511,28 @@ nm256_read_block (struct nm256_info *card)
 }
 #undef MIN
 
-/* Initialize the hardware and various other card data we'll need
-   later. */
+/* 
+ * Initialize the hardware. 
+ */
 static void
 nm256_initHw (struct nm256_info *card)
 {
-    int x;
-
-    card->playbackBufferSize = 16384;
-    card->recordBufferSize = 16384;
-
-    card->coeffBuf = card->bufend - NM_MAX_COEFFICIENT;
-    card->abuf2 = card->coeffBuf - card->recordBufferSize;
-    card->abuf1 = card->abuf2 - card->playbackBufferSize;
-    card->allCoeffBuf = card->abuf2 - (NM_TOTAL_COEFF_COUNT * 4);
-
-    /* Fixed setting. */
-    card->mixer = NM_MIXER_BASE;
-
-    card->playing = 0;
-    card->is_open_play = 0;
-    card->curPlayPos = 0;
-
-    card->recording = 0;
-    card->is_open_record = 0;
-    card->curRecPos = 0;
-
-    card->coeffsCurrent = 0;
-
-    card->opencnt[0] = 0; card->opencnt[1] = 0;
-
     /* Reset everything. */
-    nm256_writePort8 (card, 2, 0, 0x11);
-
-    /* Disable recording. */
-    nm256_writePort8 (card, 2, NM_RECORD_ENABLE_REG, 0);
+    nm256_writePort8 (card, 2, 0x0, 0x11);
     nm256_writePort16 (card, 2, 0x214, 0);
 
-    /* Reasonable default settings, but largely unnecessary. */
-    for (x = 0; x < 2; x++) {
-       card->sinfo[x].bits = 8;
-       card->sinfo[x].stereo = 0;
-       card->sinfo[x].samplerate = 8000;
-    }
+    stopRecord (card);
+    stopPlay (card);
 }
 
-/* Handle a potential interrupt for the device referred to by DEV_ID. */
+/* 
+ * Handle a potential interrupt for the device referred to by DEV_ID. 
+ *
+ * I don't like the cut-n-paste job here either between the two routines,
+ * but there are sufficient differences between the two interrupt handlers
+ * that parameterizing it isn't all that great either.  (Could use a macro,
+ * I suppose...yucky bleah.)
+ */
 
 static void
 nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
@@ -460,14 +551,32 @@ nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
     /* Not ours. */
     if (status == 0) {
        if (badintrcount++ > 1000) {
-           printk (KERN_ERR "NM256: Releasing interrupt, over 1000 invalid interrupts\n");
-           nm256_releaseInterrupt (card);
+           /*
+            * I'm not sure if the best thing is to stop the card from
+            * playing or just release the interrupt (after all, we're in
+            * a bad situation, so doing fancy stuff may not be such a good
+            * idea).
+            *
+            * I worry about the card engine continuing to play noise
+            * over and over, however--that could become a very
+            * obnoxious problem.  And we know that when this usually
+            * happens things are fairly safe, it just means the user's
+            * inserted a PCMCIA card and someone's spamming us with IRQ 9s.
+            */
+
+           if (card->playing)
+               stopPlay (card);
+           if (card->recording)
+               stopRecord (card);
+           badintrcount = 0;
        }
        return;
     }
 
     badintrcount = 0;
 
+    /* Rather boring; check for individual interrupts and process them. */
+
     if (status & NM_PLAYBACK_INT) {
        status &= ~NM_PLAYBACK_INT;
        NM_ACK_INT (card, NM_PLAYBACK_INT);
@@ -505,6 +614,7 @@ nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
        nm256_writePort8 (card, 2, 0x400, cbyte & ~2);
     }
 
+    /* Unknown interrupt. */
     if (status) {
        printk (KERN_ERR "NM256: Fire in the hole! Unknown status 0x%x\n",
                status);
@@ -513,8 +623,11 @@ nm256_interrupt (int irq, void *dev_id, struct pt_regs *dummy)
     }
 }
 
-/* Handle a potential interrupt for the device referred to by DEV_ID.
-   This handler is for the 256ZX.  */
+/*
+ * Handle a potential interrupt for the device referred to by DEV_ID.
+ * This handler is for the 256ZX, and is very similar to the non-ZX
+ * routine.
+ */
 
 static void
 nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy)
@@ -534,13 +647,33 @@ nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy)
     if (status == 0) {
        if (badintrcount++ > 1000) {
            printk (KERN_ERR "NM256: Releasing interrupt, over 1000 invalid interrupts\n");
-           nm256_releaseInterrupt (card);
+           /*
+            * I'm not sure if the best thing is to stop the card from
+            * playing or just release the interrupt (after all, we're in
+            * a bad situation, so doing fancy stuff may not be such a good
+            * idea).
+            *
+            * I worry about the card engine continuing to play noise
+            * over and over, however--that could become a very
+            * obnoxious problem.  And we know that when this usually
+            * happens things are fairly safe, it just means the user's
+            * inserted a PCMCIA card and someone's spamming us with 
+            * IRQ 9s.
+            */
+
+           if (card->playing)
+               stopPlay (card);
+           if (card->recording)
+               stopRecord (card);
+           badintrcount = 0;
        }
        return;
     }
 
     badintrcount = 0;
 
+    /* Rather boring; check for individual interrupts and process them. */
+
     if (status & NM2_PLAYBACK_INT) {
        status &= ~NM2_PLAYBACK_INT;
        NM2_ACK_INT (card, NM2_PLAYBACK_INT);
@@ -577,6 +710,7 @@ nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy)
        nm256_writePort8 (card, 2, 0x400, cbyte & ~2);
     }
 
+    /* Unknown interrupt. */
     if (status) {
        printk (KERN_ERR "NM256: Fire in the hole! Unknown status 0x%x\n",
                status);
@@ -585,7 +719,9 @@ nm256_interrupt_zx (int irq, void *dev_id, struct pt_regs *dummy)
     }
 }
 
-/* Request our interrupt. */
+/* 
+ * Request our interrupt.
+ */
 static int
 nm256_grabInterrupt (struct nm256_info *card)
 {
@@ -599,7 +735,9 @@ nm256_grabInterrupt (struct nm256_info *card)
     return 0;
 }
 
-/* Release our interrupt. */
+/* 
+ * Release our interrupt. 
+ */
 static int
 nm256_releaseInterrupt (struct nm256_info *card)
 {
@@ -614,6 +752,11 @@ nm256_releaseInterrupt (struct nm256_info *card)
     return 0;
 }
 
+/*
+ * Waits for the mixer to become ready to be written; returns a zero value
+ * if it timed out.
+ */
+
 static int
 nm256_isReady (struct ac97_hwint *dev)
 {
@@ -628,26 +771,25 @@ nm256_isReady (struct ac97_hwint *dev)
        return 0;
     }
 
-    if (card->rev == REV_NM256AV) {
-       testaddr = 0xa06;
-       testb = 0x0100;
-    } else if (card->rev == REV_NM256ZX) {
-       testaddr = 0xa08;
-       testb = 0x0800;
-    } else {
-       return -1;
-    }
+    testaddr = card->mixer_status_offset;
+    testb = card->mixer_status_mask;
 
-    while (t2-- > 0) {
-       if ((nm256_readPort16 (card, 2, testaddr) & testb) == 0) {
+    /* 
+     * Loop around waiting for the mixer to become ready. 
+     */
+    while (! done && t2-- > 0) {
+       if ((nm256_readPort16 (card, 2, testaddr) & testb) == 0)
            done = 1;
-           break;
-       }
-       udelay (100);
+       else
+           udelay (100);
     }
     return done;
 }
 
+/*
+ * Return the contents of the AC97 mixer register REG.  Returns a positive
+ * value if successful, or a negative error code.
+ */
 static int
 nm256_readAC97Reg (struct ac97_hwint *dev, u8 reg)
 {
@@ -663,6 +805,7 @@ nm256_readAC97Reg (struct ac97_hwint *dev, u8 reg)
 
        nm256_isReady (dev);
        res = nm256_readPort16 (card, 2, card->mixer + reg);
+       /* Magic delay.  Bleah yucky.  */
         udelay (1000);
        return res;
     }
@@ -670,6 +813,10 @@ nm256_readAC97Reg (struct ac97_hwint *dev, u8 reg)
        return -EINVAL;
 }
 
+/* 
+ * Writes VALUE to AC97 mixer register REG.  Returns 0 if successful, or
+ * a negative error code. 
+ */
 static int
 nm256_writeAC97Reg (struct ac97_hwint *dev, u8 reg, u16 value)
 {
@@ -708,6 +855,13 @@ nm256_writeAC97Reg (struct ac97_hwint *dev, u8 reg, u16 value)
     return ! done;
 }
 
+/* 
+ * Initial register values to be written to the AC97 mixer.
+ * While most of these are identical to the reset values, we do this
+ * so that we have most of the register contents cached--this avoids
+ * reading from the mixer directly (which seems to be problematic,
+ * probably due to ignorance).
+ */
 struct initialValues 
 {
     unsigned short port;
@@ -716,23 +870,24 @@ struct initialValues
 
 static struct initialValues nm256_ac97_initial_values[] = 
 {
-    { 0x0002, 0x8000 },
-    { 0x0004, 0x0000 },
-    { 0x0006, 0x0000 },
-    { 0x000A, 0x0000 },
-    { 0x000C, 0x0008 },
-    { 0x000E, 0x8008 },
-    { 0x0010, 0x8808 },
-    { 0x0012, 0x8808 },
-    { 0x0014, 0x8808 },
-    { 0x0016, 0x8808 },
-    { 0x0018, 0x0808 },
-    { 0x001A, 0x0000 },
-    { 0x001C, 0x0B0B },
-    { 0x0020, 0x0000 },
+    { AC97_MASTER_VOL_STEREO, 0x8000 },
+    { AC97_HEADPHONE_VOL,     0x8000 },
+    { AC97_MASTER_VOL_MONO,   0x0000 },
+    { AC97_PCBEEP_VOL,        0x0000 },
+    { AC97_PHONE_VOL,         0x0008 },
+    { AC97_MIC_VOL,           0x8000 },
+    { AC97_LINEIN_VOL,        0x8808 },
+    { AC97_CD_VOL,            0x8808 },
+    { AC97_VIDEO_VOL,         0x8808 },
+    { AC97_AUX_VOL,           0x8808 },
+    { AC97_PCMOUT_VOL,        0x0808 },
+    { AC97_RECORD_SELECT,     0x0000 },
+    { AC97_RECORD_GAIN,       0x0B0B },
+    { AC97_GENERAL_PURPOSE,   0x0000 },
     { 0xffff, 0xffff }
 };
 
+/* Initialize the AC97 into a known state.  */
 static int
 nm256_resetAC97 (struct ac97_hwint *dev)
 {
@@ -744,22 +899,28 @@ nm256_resetAC97 (struct ac97_hwint *dev)
        return -EINVAL;
     }
 
-    /* Reset the card.  'Tis magic!  */
+    /* Reset the mixer.  'Tis magic!  */
     nm256_writePort8 (card, 2, 0x6c0, 1);
     nm256_writePort8 (card, 2, 0x6cc, 0x87);
     nm256_writePort8 (card, 2, 0x6cc, 0x80);
     nm256_writePort8 (card, 2, 0x6cc, 0x0);
 
-    for (x = 0; nm256_ac97_initial_values[x].port != 0xffff; x++) {
-       ac97_put_register (dev,
-                          nm256_ac97_initial_values[x].port, 
-                          nm256_ac97_initial_values[x].value);
+    if (! card->mixer_values_init) {
+       for (x = 0; nm256_ac97_initial_values[x].port != 0xffff; x++) {
+           ac97_put_register (dev,
+                              nm256_ac97_initial_values[x].port,
+                              nm256_ac97_initial_values[x].value);
+           card->mixer_values_init = 1;
+       }
     }
 
     return 0;
 }
 
-/* We don't do anything special here.  */
+/*
+ * We don't do anything particularly special here; it just passes the
+ * mixer ioctl to the AC97 driver.
+ */
 static int
 nm256_default_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg)
 {
@@ -776,7 +937,12 @@ static struct mixer_operations nm256_mixer_operations = {
     nm256_default_mixer_ioctl
 };
 
-/* I "love" C sometimes.  Got braces?  */
+/*
+ * Default settings for the OSS mixer.  These are set last, after the
+ * mixer is initialized.
+ *
+ * I "love" C sometimes.  Got braces?
+ */
 static struct ac97_mixer_value_list mixer_defaults[] = {
     { SOUND_MIXER_VOLUME,  { { 85, 85 } } },
     { SOUND_MIXER_SPEAKER, { { 100 } } },
@@ -785,6 +951,8 @@ static struct ac97_mixer_value_list mixer_defaults[] = {
     { -1,                  {  { 0,  0 } } }
 };
 
+
+/* Installs the AC97 mixer into CARD.  */
 static int
 nm256_install_mixer (struct nm256_info *card)
 {
@@ -814,36 +982,67 @@ nm256_install_mixer (struct nm256_info *card)
     return 0;
 }
 
-/* See if the signature left by the NM256 BIOS is intact; if so, we use
-   the associated address as the end of our buffer. */
+/* Perform a full reset on the hardware; this is invoked when an APM
+   resume event occurs.  */
 static void
-nm256_peek_for_sig (struct nm256_info *card, u32 port1addr)
+nm256_full_reset (struct nm256_info *card)
 {
-    char *temp = ioremap_nocache (port1addr + card->port1_end - 0x0400, 16);
+    nm256_initHw (card);
+    ac97_reset (&(card->mdev));
+}
+
+/* 
+ * See if the signature left by the NM256 BIOS is intact; if so, we use
+ * the associated address as the end of our audio buffer in the video
+ * RAM.
+ */
+
+static void
+nm256_peek_for_sig (struct nm256_info *card)
+{
+    u32 port1offset 
+       = card->port[0].physaddr + card->port[0].end_offset - 0x0400;
+    /* The signature is located 1K below the end of video RAM.  */
+    char *temp = ioremap_nocache (port1offset, 16);
+    /* Default buffer end is 5120 bytes below the top of RAM.  */
+    u32 default_value = card->port[0].end_offset - 0x1400;
     u32 sig;
 
+    /* Install the default value first, so we don't have to repeatedly
+       do it if there is a problem.  */
+    card->port[0].end_offset = default_value;
+
     if (temp == NULL) {
        printk (KERN_ERR "NM256: Unable to scan for card signature in video RAM\n");
        return;
     }
-    memcpy_fromio (&sig, temp, sizeof (u32));
-    if ((sig & 0xffff0000) == 0x4e4d0000) {
-       memcpy_fromio (&(card->bufend), temp + 4, sizeof (u32));
+    sig = readl (temp);
+    if ((sig & NM_SIG_MASK) == NM_SIGNATURE) {
+       u32 pointer = readl (temp + 4);
+
+       /*
+        * If it's obviously invalid, don't use it (the port already has a
+        * suitable default value set).
+        */
+       if (pointer != 0xffffffff)
+           card->port[0].end_offset = pointer;
+
        printk (KERN_INFO "NM256: Found card signature in video RAM: 0x%x\n",
-               card->bufend);
+               pointer);
     }
 
     release_region ((unsigned long) temp, 16);
 }
 
-/* Install a driver for the soundcard referenced by PCIDEV. */
+/* 
+ * Install a driver for the PCI device referenced by PCIDEV.
+ * VERSTR is a human-readable version string.
+ */
 
 static int
 nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr)
 {
     struct nm256_info *card;
-    u32 port1addr = (pcidev->base_address[0] & PCI_BASE_ADDRESS_MEM_MASK);
-    u32 port2addr = (pcidev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK);
     int x;
 
     card = kmalloc (sizeof (struct nm256_info), GFP_KERNEL);
@@ -857,52 +1056,85 @@ nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr)
     card->recording = 0;
     card->rev = rev;
 
-    /* The NM256 has two memory ports.  The first port is nothing
-       more than a chunk of video RAM, which is used as the I/O ring
-       buffer.  The second port has the actual juicy stuff (like the
-       mixer and the playback engine control registers). */
+    /* Init the memory port info.  */
+    for (x = 0; x < 2; x++) {
+       card->port[x].physaddr = RSRCADDRESS (pcidev, x);
+       card->port[x].ptr = NULL;
+       card->port[x].start_offset = 0;
+       card->port[x].end_offset = 0;
+    }
 
-    card->ports[1] = ioremap_nocache (port2addr, NM_PORT2_SIZE);
+    /* Port 2 is easy.  */
+    card->port[1].start_offset = 0;
+    card->port[1].end_offset = NM_PORT2_SIZE;
 
-    if (card->ports[1] == NULL) {
-       printk (KERN_ERR "NM256: Unable to remap port 2\n");
+    /* Yuck.  But we have to map in port 2 so we can check how much RAM the
+       card has.  */
+    if (nm256_remap_ports (card)) {
        kfree_s (card, sizeof (struct nm256_info));
        return 0;
     }
 
+    /* 
+     * The NM256 has two memory ports.  The first port is nothing
+     * more than a chunk of video RAM, which is used as the I/O ring
+     * buffer.  The second port has the actual juicy stuff (like the
+     * mixer and the playback engine control registers).
+     */
+
     if (card->rev == REV_NM256AV) {
-       card->port1_end = 2560 * 1024;
+       /* Ok, try to see if this is a non-AC97 version of the hardware. */
+       int pval = nm256_readPort16 (card, 2, NM_MIXER_PRESENCE);
+       if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) {
+           if (! force_load) {
+               printk (KERN_ERR "NM256: This doesn't look to me like the AC97-compatible version.\n");
+               printk (KERN_ERR "       You can force the driver to load by passing in the module\n");
+               printk (KERN_ERR "       parameter:\n");
+               printk (KERN_ERR "              force_ac97 = 1\n");
+               printk (KERN_ERR "\n");
+               printk (KERN_ERR "       More likely, you should be using the appropriate SB-16 or\n");
+               printk (KERN_ERR "       CS4232 driver instead.  (If your BIOS has settings for\n");
+               printk (KERN_ERR "       IRQ and/or DMA for the sound card, this is *not* the correct\n");
+               printk (KERN_ERR "       driver to use.)\n");
+               nm256_release_ports (card);
+               kfree_s (card, sizeof (struct nm256_info));
+               return 0;
+           }
+           else {
+               printk (KERN_INFO "NM256: Forcing driver load as per user request.\n");
+           }
+       }
+       else {
+           printk (KERN_INFO "NM256: Congratulations. You're not running Eunice.\n");
+       }
+       card->port[0].end_offset = 2560 * 1024;
        card->introutine = nm256_interrupt;
+       card->mixer_status_offset = NM_MIXER_STATUS_OFFSET;
+       card->mixer_status_mask = NM_MIXER_READY_MASK;
     } 
     else {
+       /* Not sure if there is any relevant detect for the ZX or not.  */
        if (nm256_readPort8 (card, 2, 0xa0b) != 0)
-           card->port1_end = 6144 * 1024;
+           card->port[0].end_offset = 6144 * 1024;
        else
-           card->port1_end = 4096 * 1024;
+           card->port[0].end_offset = 4096 * 1024;
 
        card->introutine = nm256_interrupt_zx;
+       card->mixer_status_offset = NM2_MIXER_STATUS_OFFSET;
+       card->mixer_status_mask = NM2_MIXER_READY_MASK;
     }
 
-    /* Default value. */
-    card->bufend = card->port1_end - 0x1400;
-
-    if (buffertop >= 98304 && buffertop < card->port1_end)
-       card->bufend = buffertop;
+    if (buffertop >= 98304 && buffertop < card->port[0].end_offset)
+       card->port[0].end_offset = buffertop;
     else
-       nm256_peek_for_sig (card, port1addr);
+       nm256_peek_for_sig (card);
 
-    card->port1_start = card->bufend - 98304;
+    card->port[0].start_offset = card->port[0].end_offset - 98304;
 
     printk (KERN_INFO "NM256: Mapping port 1 from 0x%x - 0x%x\n",
-           card->port1_start, card->port1_end);
-
-    card->ports[0] =
-       ioremap_nocache (port1addr + card->port1_start,
-                        card->port1_end - card->port1_start);
+           card->port[0].start_offset, card->port[0].end_offset);
 
-    if (card->ports[0] == NULL) {
-       printk (KERN_ERR "NM256: Unable to remap port 1\n");
-       release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE);
+    if (nm256_remap_ports (card)) {
        kfree_s (card, sizeof (struct nm256_info));
        return 0;
     }
@@ -913,9 +1145,7 @@ nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr)
     card->has_irq = 0;
 
     if (nm256_grabInterrupt (card) != 0) {
-       release_region ((unsigned long) card->ports[0], 
-                       card->port1_end - card->port1_start);
-       release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE);
+       nm256_release_ports (card);
        kfree_s (card, sizeof (struct nm256_info));
        return 0;
     }
@@ -926,10 +1156,36 @@ nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr)
      * Init the board.
      */
 
+    card->playbackBufferSize = 16384;
+    card->recordBufferSize = 16384;
+
+    card->coeffBuf = card->port[0].end_offset - NM_MAX_COEFFICIENT;
+    card->abuf2 = card->coeffBuf - card->recordBufferSize;
+    card->abuf1 = card->abuf2 - card->playbackBufferSize;
+    card->allCoeffBuf = card->abuf2 - (NM_TOTAL_COEFF_COUNT * 4);
+
+    /* Fixed setting. */
+    card->mixer = NM_MIXER_OFFSET;
+    card->mixer_values_init = 0;
+
+    card->is_open_play = 0;
+    card->is_open_record = 0;
+
+    card->coeffsCurrent = 0;
+
+    card->opencnt[0] = 0; card->opencnt[1] = 0;
+
+    /* Reasonable default settings, but largely unnecessary. */
+    for (x = 0; x < 2; x++) {
+       card->sinfo[x].bits = 8;
+       card->sinfo[x].stereo = 0;
+       card->sinfo[x].samplerate = 8000;
+    }
+
     nm256_initHw (card);
 
     for (x = 0; x < 2; x++) {
-       if ((card->dev[x] = 
+       if ((card->dev[x] =
             sound_install_audiodrv(AUDIO_DRIVER_VERSION,
                                    "NM256", &nm256_audio_driver,
                                    sizeof(struct audio_driver),
@@ -942,9 +1198,7 @@ nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr)
        }
        else {
            printk(KERN_ERR "NM256: Too many PCM devices available\n");
-           release_region ((unsigned long) card->ports[0], 
-                           card->port1_end - card->port1_start);
-           release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE);
+           nm256_release_ports (card);
            kfree_s (card, sizeof (struct nm256_info));
            return 0;
        }
@@ -966,6 +1220,48 @@ nm256_install(struct pci_dev *pcidev, enum nm256rev rev, char *verstr)
     return 1;
 }
 
+
+#ifdef CONFIG_APM
+/*
+ * APM event handler, so the card is properly reinitialized after a power
+ * event.
+ */
+static int
+handle_apm_event (apm_event_t event)
+{
+    static int down = 0;
+
+    switch (event)
+       {
+       case APM_SYS_SUSPEND:
+       case APM_USER_SUSPEND:
+           down++;
+           break;
+       case APM_NORMAL_RESUME:
+       case APM_CRITICAL_RESUME:
+           if (down)
+               {
+                   struct nm256_info *crd;
+
+                   down = 0;
+                   for (crd = nmcard_list;  crd != NULL; crd = crd->next_card)
+                       {
+                           int playing = crd->playing;
+                           nm256_full_reset (crd);
+                           /*
+                            * A little ugly, but that's ok; pretend the
+                            * block we were playing is done. 
+                            */
+                           if (playing)
+                               DMAbuf_outputintr (crd->dev_for_play, 1);
+                       }
+               }
+           break;
+       }
+    return 0;
+}
+#endif
+
 /*
  *     This loop walks the PCI configuration database and finds where
  *     the sound cards are.
@@ -995,6 +1291,10 @@ init_nm256(void)
     if (count == 0)
        return -ENODEV;
 
+#ifdef CONFIG_APM
+    apm_register_callback (&handle_apm_event);
+#endif
+
     printk (KERN_INFO "Done installing NM256 audio driver.\n");
     return 0;
 }
@@ -1030,10 +1330,13 @@ nm256_audio_open(int dev, int mode)
     if (! ((mode & OPEN_READ) || (mode & OPEN_WRITE)))
        return -EIO;
 
-    /* If it's open for both read and write, and the card's currently
-       being read or written to, then do the opposite of what has
-       already been done.  Otherwise, don't specify any mode until the
-       user actually tries to do I/O. */
+    /*
+     * If it's open for both read and write, and the card's currently
+     * being read or written to, then do the opposite of what has
+     * already been done.  Otherwise, don't specify any mode until the
+     * user actually tries to do I/O.  (Some programs open the device
+     * for both read and write, but only actually do reading or writing.)
+     */
 
     if ((mode & OPEN_WRITE) && (mode & OPEN_READ)) {
        if (card->is_open_play)
@@ -1107,6 +1410,7 @@ nm256_audio_close(int dev)
     }
 }
 
+/* Standard ioctl handler. */
 static int
 nm256_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
@@ -1124,6 +1428,11 @@ nm256_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
     else
        w = 1;
 
+    /* 
+     * The code here is messy.  There are probably better ways to do
+     * it.  (It should be possible to handle it the same way the AC97 mixer 
+     * is done.)
+     */
     switch (cmd)
        {
        case SOUND_PCM_WRITE_RATE:
@@ -1195,8 +1504,12 @@ nm256_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
     return put_user(ret, (int *) arg);
 }
 
-/* Given the dev DEV and an associated physical buffer PHYSBUF, return
-   a pointer to the actual buffer in kernel space. */
+/*
+ * Given the sound device DEV and an associated physical buffer PHYSBUF, 
+ * return a pointer to the actual buffer in kernel space. 
+ *
+ * This routine should exist as part of the soundcore routines.
+ */
 
 static char *
 nm256_getDMAbuffer (int dev, unsigned long physbuf)
@@ -1240,9 +1553,10 @@ nm256_audio_output_block(int dev, unsigned long physbuf,
     }
 }
 
+/* Ditto, but do recording instead.  */
 static void
 nm256_audio_start_input(int dev, unsigned long physbuf, int count,
-                         int intrflag)
+                       int intrflag)
 {
     struct nm256_info *card = nm256_find_card (dev);
 
@@ -1254,6 +1568,12 @@ nm256_audio_start_input(int dev, unsigned long physbuf, int count,
     }
 }
 
+/* 
+ * Prepare for inputting samples to DEV. 
+ * Each requested buffer will be BSIZE byes long, with a total of
+ * BCOUNT buffers. 
+ */
+
 static int
 nm256_audio_prepare_for_input(int dev, int bsize, int bcount)
 {
@@ -1280,6 +1600,7 @@ nm256_audio_prepare_for_input(int dev, int bsize, int bcount)
  *  2. We get a write buffer without dma_mode setup     (dmabuf.c:1152)
  *  3. We restart a transfer                            (dmabuf.c:1324)
  */
+
 static int
 nm256_audio_prepare_for_output(int dev, int bsize, int bcount)
 {
@@ -1344,12 +1665,13 @@ static int loaded = 0;
 MODULE_PARM (usecache, "i");
 MODULE_PARM (buffertop, "i");
 MODULE_PARM (nm256_debug, "i");
+MODULE_PARM (force_load, "i");
 
 int
 init_module (void)
 {
     nmcard_list = NULL;
-    printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.0\n");
+    printk (KERN_INFO "NeoMagic 256AV/256ZX audio driver, version 1.1\n");
 
     if (init_nm256 () == 0) {
        SOUND_LOCK;
@@ -1374,9 +1696,7 @@ cleanup_module (void)
            stopRecord (card);
            if (card->has_irq)
                free_irq (card->irq, card);
-           release_region ((unsigned long) card->ports[0], 
-                           card->port1_end - card->port1_start);
-           release_region ((unsigned long) card->ports[1], NM_PORT2_SIZE);
+           nm256_release_ports (card);
            sound_unload_mixerdev (card->mixer_oss_dev);
            sound_unload_audiodev (card->dev[0]);
            sound_unload_audiodev (card->dev[1]);
@@ -1385,6 +1705,9 @@ cleanup_module (void)
        }
        nmcard_list = NULL;
     }
+#ifdef CONFIG_APM
+    apm_unregister_callback (&handle_apm_event);
+#endif
 }
 #endif
 \f
index c8fc7ecbe6c8d44ea436fc5836ead5228d61cf92..0ceecc20077ba75aef3412529bf8fde1a9530391 100644 (file)
@@ -4622,7 +4622,8 @@ nm256_getStartOffset (u8 which)
 }
 
 static void
-nm256_loadOneCoefficient (struct nm256_info *card, u32 port, u16 which)
+nm256_loadOneCoefficient (struct nm256_info *card, int devnum, u32 port, 
+                         u16 which)
 {
     u32 coeffBuf = (which < 8) ? card->coeffBuf : card->allCoeffBuf;
     u16 offset = nm256_getStartOffset (which);
@@ -4631,11 +4632,14 @@ nm256_loadOneCoefficient (struct nm256_info *card, u32 port, u16 which)
     card->coeffsCurrent = 0;
 
     if (nm256_debug)
-       printk (KERN_INFO "NM256: Loading coefficient buffer 0x%x-0x%x with coefficient %d\n",
-               coeffBuf, coeffBuf + size - 1, which);
+       printk (KERN_INFO "NM256: Loading coefficient buffer 0x%x-0x%x with coefficient %d, size %d, port 0x%x\n",
+               coeffBuf, coeffBuf + size - 1, which, size, port);
     nm256_writeBuffer8 (card, coefficients + offset, 1, coeffBuf, size);
     nm256_writePort32 (card, 2, port + 0, coeffBuf);
-    nm256_writePort32 (card, 2, port + 4, coeffBuf + size - 1);
+    /* ???  Record seems to behave differently than playback.  */
+    if (devnum == 0)
+       size--;
+    nm256_writePort32 (card, 2, port + 4, coeffBuf + size);
 }
 
 static void
@@ -4663,7 +4667,7 @@ nm256_loadCoefficient (struct nm256_info *card, int which, int number)
        number += 8;
 
     if (! nm256_cachedCoefficients (card))
-       nm256_loadOneCoefficient (card, addrs[which], number);
+       nm256_loadOneCoefficient (card, which, addrs[which], number);
     else {
        u32 base = card->allCoeffBuf;
        u32 offset = nm256_getStartOffset (number);
index 6c8814567ab2d74a8d135ad1d7e32c386715a42b..92270e3c9683ceac91ce322c3f1e8f4e28100169 100644 (file)
@@ -166,7 +166,7 @@ void adfs_read_inode (struct inode *inode)
        sb = inode->i_sb;
        inode->i_uid = sb->u.adfs_sb.s_uid;
        inode->i_gid = sb->u.adfs_sb.s_gid;
-       inode->i_version = ++event;
+       inode->i_version = ++global_event;
 
        if (adfs_inode_validate_no (sb, inode->i_ino & 0xffffff00)) {
                adfs_error (sb, "adfs_read_inode",
index 9b05ec062ae1bff5e8530320a7cb0d511fc0dd5f..39fe0e6f096047a3111ff02a85842b4272547049 100644 (file)
@@ -379,13 +379,13 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
                                                FILE_END(link_bh->b_data,link)->link_chain;
                FILE_END(link_bh->b_data,link)->link_chain   = cpu_to_be32(inode->i_ino);
                affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
-               link->i_version = ++event;
+               link->i_version = ++global_event;
                mark_inode_dirty(link);
                mark_buffer_dirty(link_bh,1);
        }
        affs_fix_checksum(AFFS_I2BSIZE(inode),inode_bh->b_data,5);
        affs_fix_checksum(AFFS_I2BSIZE(dir),dir_bh->b_data,5);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        dir->i_mtime   = dir->i_atime = dir->i_ctime = CURRENT_TIME;
        unlock_super(inode->i_sb);
 
index 48e95180000f6b067d809083fbe7ec623fd1c333..e823f2eb50aa67dc60f4ad4d9603b1f47ba41bf5 100644 (file)
@@ -247,7 +247,7 @@ affs_unlink(struct inode *dir, struct dentry *dentry)
        
        inode->i_nlink = retval;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_inode_dirty(inode);
        d_delete(dentry);
        mark_inode_dirty(dir);
@@ -285,7 +285,7 @@ affs_create(struct inode *dir, struct dentry *dentry, int mode)
        inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
        d_instantiate(dentry,inode);
        mark_inode_dirty(inode);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_inode_dirty(dir);
 out:
        return error;
@@ -319,7 +319,7 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
        d_instantiate(dentry,inode);
        mark_inode_dirty(inode);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_inode_dirty(dir);
 out:
        return error;
@@ -372,7 +372,7 @@ affs_rmdir(struct inode *dir, struct dentry *dentry)
        inode->i_nlink = retval;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        retval         = 0;
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_inode_dirty(dir);
        mark_inode_dirty(inode);
        d_delete(dentry);
@@ -450,7 +450,7 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
        if (error)
                goto out_release;
        d_instantiate(dentry,inode);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_inode_dirty(dir);
 
 out:
@@ -504,7 +504,7 @@ affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
        if (error)
                inode->i_nlink = 0;
        else {
-               dir->i_version = ++event;
+               dir->i_version = ++global_event;
                mark_inode_dirty(dir);
                mark_inode_dirty(oldinode);
                oldinode->i_count++;
@@ -579,8 +579,8 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
 
        new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime
                           = old_dir->i_mtime = CURRENT_TIME;
-       new_dir->i_version = ++event;
-       old_dir->i_version = ++event;
+       new_dir->i_version = ++global_event;
+       old_dir->i_version = ++global_event;
        retval             = 0;
        mark_inode_dirty(new_dir);
        mark_inode_dirty(old_dir);
index e8d2c543f11d35df1e2976c1a1bd0ded6b62a1e3..1f057529704f18c4617e42d8564534e49fd4dd1b 100644 (file)
@@ -361,6 +361,43 @@ resume:
        return (count > 1); /* remaining users? */
 }
 
+/*
+ * Search for at least 1 mount point in the dentry's subdirs.
+ * We descend to the next level whenever the d_subdirs
+ * list is non-empty and continue searching.
+ */
+int have_submounts(struct dentry *parent)
+{
+       struct dentry *this_parent = parent;
+       struct list_head *next;
+
+       if (parent->d_mounts != parent)
+               return 1;
+repeat:
+       next = this_parent->d_subdirs.next;
+resume:
+       while (next != &this_parent->d_subdirs) {
+               struct list_head *tmp = next;
+               struct dentry *dentry = list_entry(tmp, struct dentry, d_child);                next = tmp->next;
+               /* Have we found a mount point ? */
+               if (dentry->d_mounts != dentry)
+                       return 1;
+               if (!list_empty(&dentry->d_subdirs)) {
+                       this_parent = dentry;
+                       goto repeat;
+               }
+       }
+       /*
+        * All done at this level ... ascend and resume the search.
+        */
+       if (this_parent != parent) {
+               next = this_parent->d_child.next;
+               this_parent = this_parent->d_parent;
+               goto resume;
+       }
+       return 0; /* No mount points found in tree */
+}
+
 /*
  * Search the dentry child list for the specified parent,
  * and move any unused dentries to the end of the unused
index 9ce7a231176e40ca1b9aea8da3f42096024b3076..f13984544d18324a0297244d640dc48775388e24 100644 (file)
@@ -131,7 +131,7 @@ static long long ext2_file_lseek(
        if (offset != file->f_pos) {
                file->f_pos = offset;
                file->f_reada = 0;
-               file->f_version = ++event;
+               file->f_version = ++global_event;
        }
        return offset;
 }
index c50737d675b8952cf2a109483f73676fa197d17e..f9a924b40b5e371c2fdae79ef08279ac810952eb 100644 (file)
@@ -521,7 +521,7 @@ void ext2_read_inode (struct inode * inode)
        inode->u.ext2_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);
        inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat), not the fs block size */
        inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
-       inode->i_version = ++event;
+       inode->i_version = ++global_event;
        inode->u.ext2_i.i_new_inode = 0;
        inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags);
        inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);
index ecef4a91b9dbdafc7edaf77d76054aeea49d2442..24cb4557258c7f0f7d2e46d72586692c4af2d7ee 100644 (file)
@@ -301,7 +301,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir,
                        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
                        dir->u.ext2_i.i_flags &= ~EXT2_BTREE_FL;
                        mark_inode_dirty(dir);
-                       dir->i_version = ++event;
+                       dir->i_version = ++global_event;
                        mark_buffer_dirty(bh, 1);
                        *res_dir = de;
                        *err = 0;
@@ -383,7 +383,7 @@ int ext2_create (struct inode * dir, struct dentry * dentry, int mode)
        if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
                                      EXT2_FEATURE_INCOMPAT_FILETYPE))
                de->file_type = EXT2_FT_REG_FILE;
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -412,7 +412,7 @@ int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
        if (!bh)
                goto out_no_entry;
        de->inode = cpu_to_le32(inode->i_ino);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        if (S_ISREG(inode->i_mode)) {
                inode->i_op = &ext2_file_inode_operations;
                if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
@@ -511,7 +511,7 @@ int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode)
        if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
                                      EXT2_FEATURE_INCOMPAT_FILETYPE))
                de->file_type = EXT2_FT_DIR;
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -619,7 +619,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
                goto end_rmdir;
 
        retval = ext2_delete_entry (de, bh);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        if (retval)
                goto end_rmdir;
        mark_buffer_dirty(bh, 1);
@@ -631,7 +631,7 @@ int ext2_rmdir (struct inode * dir, struct dentry *dentry)
                ext2_warning (inode->i_sb, "ext2_rmdir",
                              "empty directory has nlink!=2 (%d)",
                              inode->i_nlink);
-       inode->i_version = ++event;
+       inode->i_version = ++global_event;
        inode->i_nlink = 0;
        inode->i_size = 0;
        mark_inode_dirty(inode);
@@ -674,7 +674,7 @@ int ext2_unlink(struct inode * dir, struct dentry *dentry)
        retval = ext2_delete_entry (de, bh);
        if (retval)
                goto end_unlink;
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -747,7 +747,7 @@ int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symnam
        if (EXT2_HAS_INCOMPAT_FEATURE(dir->i_sb,
                                      EXT2_FEATURE_INCOMPAT_FILETYPE))
                de->file_type = EXT2_FT_SYMLINK;
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -800,7 +800,7 @@ int ext2_link (struct dentry * old_dentry,
                else if (S_ISFIFO(inode->i_mode))  
                        de->file_type = EXT2_FT_FIFO;
        }
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -880,7 +880,7 @@ int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
                if (!new_bh)
                        goto end_rename;
        }
-       new_dir->i_version = ++event;
+       new_dir->i_version = ++global_event;
 
        /*
         * Like most other Unix systems, set the ctime for inodes on a
@@ -899,7 +899,7 @@ int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
        
        ext2_delete_entry (old_de, old_bh);
 
-       old_dir->i_version = ++event;
+       old_dir->i_version = ++global_event;
        if (new_inode) {
                new_inode->i_nlink--;
                new_inode->i_ctime = CURRENT_TIME;
index 9bdbc37fc83f9d1f77682db8f3404d48a8313ec8..f75582d32fbdb221310ed50457755314d8998a81 100644 (file)
@@ -370,7 +370,7 @@ static void fat_read_root(struct inode *inode)
        MSDOS_I(inode)->i_fat_inode = inode;
        inode->i_uid = MSDOS_SB(sb)->options.fs_uid;
        inode->i_gid = MSDOS_SB(sb)->options.fs_gid;
-       inode->i_version = ++event;
+       inode->i_version = ++global_event;
        MSDOS_I(inode)->i_last_pos = 0;
        inode->i_mode = (S_IRWXUGO & ~MSDOS_SB(sb)->options.fs_umask) | S_IFDIR;
        inode->i_op = MSDOS_SB(sb)->dir_ops;
@@ -759,7 +759,7 @@ static void fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de)
        MSDOS_I(inode)->i_fat_inode = inode;
        inode->i_uid = MSDOS_SB(sb)->options.fs_uid;
        inode->i_gid = MSDOS_SB(sb)->options.fs_gid;
-       inode->i_version = ++event;
+       inode->i_version = ++global_event;
        if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) {
                MSDOS_I(inode)->i_last_pos = 0;
                inode->i_mode = MSDOS_MKMODE(de->attr,S_IRWXUGO &
index f7679dba374dead68e8843b0bc93aaca31a07046..ca1ed4cc1de4a99bf454d88e8f04b8d8cd40e4af 100644 (file)
@@ -80,7 +80,7 @@ struct file * get_empty_filp(void)
        new_one:
                memset(f, 0, sizeof(*f));
                f->f_count = 1;
-               f->f_version = ++event;
+               f->f_version = ++global_event;
                f->f_uid = current->fsuid;
                f->f_gid = current->fsgid;
                put_inuse(f);
index b355408c92758903859737d85fa1a5b73a07150c..17172314a2e297a83edca5904fbbd44047a19210 100644 (file)
@@ -88,7 +88,7 @@ static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir)
                                        ++(tmp->i_nlink);
                                }
                                tmp->i_size += HFS_I(tmp)->dir_size;
-                               tmp->i_version = ++event;
+                               tmp->i_version = ++global_event;
                        }
                        tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
                        mark_inode_dirty(tmp);
@@ -118,7 +118,7 @@ static inline void update_dirs_minus(struct hfs_cat_entry *dir, int is_dir)
                                        --(tmp->i_nlink);
                                }
                                tmp->i_size -= HFS_I(tmp)->dir_size;
-                               tmp->i_version = ++event;
+                               tmp->i_version = ++global_event;
                        }
                        tmp->i_ctime = tmp->i_mtime = CURRENT_TIME;
                        mark_inode_dirty(tmp);
index 8a855438d264faefaa991e53e593d8a34bad77c6..c67ee85780b5ed2902424995c7bf14b5aa9be869 100644 (file)
@@ -194,7 +194,7 @@ static int minix_add_entry(struct inode * dir,
                        mark_inode_dirty(dir);
                        for (i = 0; i < info->s_namelen ; i++)
                                de->name[i] = (i < namelen) ? name[i] : 0;
-                       dir->i_version = ++event;
+                       dir->i_version = ++global_event;
                        mark_buffer_dirty(bh, 1);
                        *res_dir = de;
                        break;
@@ -415,7 +415,7 @@ int minix_rmdir(struct inode * dir, struct dentry *dentry)
        if (inode->i_nlink != 2)
                printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink);
        de->inode = 0;
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        inode->i_nlink=0;
        mark_inode_dirty(inode);
@@ -449,7 +449,7 @@ int minix_unlink(struct inode * dir, struct dentry *dentry)
                inode->i_nlink=1;
        }
        de->inode = 0;
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        mark_inode_dirty(dir);
@@ -601,10 +601,10 @@ int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
        new_de->inode = old_inode->i_ino;
        old_de->inode = 0;
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
-       old_dir->i_version = ++event;
+       old_dir->i_version = ++global_event;
        mark_inode_dirty(old_dir);
        new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
-       new_dir->i_version = ++event;
+       new_dir->i_version = ++global_event;
        mark_inode_dirty(new_dir);
        if (new_inode) {
                new_inode->i_nlink--;
index be1c34dac8bb24374a48f3bc0647fc1ac5d542ac..0f32a50e015a1d7a4bc30ca570a2cb23944a8534 100644 (file)
@@ -517,7 +517,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name,
                if (error)
                        goto out;
        }
-       new_dir->i_version = ++event;
+       new_dir->i_version = ++global_event;
 
        /* There we go */
 
@@ -532,7 +532,7 @@ static int do_msdos_rename(struct inode *old_dir, char *old_name,
        else
                MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
        mark_inode_dirty(old_inode);
-       old_dir->i_version = ++event;
+       old_dir->i_version = ++global_event;
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
        mark_inode_dirty(old_dir);
        if (new_inode) {
@@ -569,7 +569,7 @@ degenerate_case:
        else
                MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
        mark_inode_dirty(old_inode);
-       old_dir->i_version = ++event;
+       old_dir->i_version = ++global_event;
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
        mark_inode_dirty(old_dir);
        return 0;
index 6bfa519dd8358e10540734090abd4bc4371f5189..8e07295b5757ebc7fad7fa1dfeb01fec73cdc3cd 100644 (file)
@@ -473,9 +473,12 @@ static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
 out_valid:
        return 1;
 out_bad:
-       d_drop(dentry);
        if (!list_empty(&dentry->d_subdirs))
                shrink_dcache_parent(dentry);
+       /* If we have submounts, don't unhash ! */
+       if (have_submounts(dentry))
+               goto out_valid;
+       d_drop(dentry);
        if (dentry->d_parent->d_inode)
                nfs_invalidate_dircache(dentry->d_parent->d_inode);
        if (inode && S_ISDIR(inode->i_mode))
index af612843fdfde90932b869b84981ed738d8fc1b3..12191ee9d0cf8dcb5b8c29eb43e24211dbb31741 100644 (file)
@@ -772,7 +772,7 @@ _nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
                fh = (u32 *) &fhandle;
                dfprintk(PAGECACHE, "            %08x%08x%08x%08x%08x%08x%08x%08x\n",
                        fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
-               if (!IS_ROOT(dentry))
+               if (!IS_ROOT(dentry) && !have_submounts(dentry))
                        d_drop(dentry);
                goto out;
        }
index 7b9bf0bf759393d09479411abad843d2b6ac87ef..a970a9e661f86c091ad413273ac53c2a830355ec 100644 (file)
@@ -29,7 +29,7 @@ static loff_t default_llseek(struct file *file, loff_t offset, int origin)
                if (offset != file->f_pos) {
                        file->f_pos = offset;
                        file->f_reada = 0;
-                       file->f_version = ++event;
+                       file->f_version = ++global_event;
                }
                retval = offset;
        }
index 7bec94a6edd69baafe445b04237f24c612ce51da..ef716e21a8be4340d9562be23e91031b64733598 100644 (file)
@@ -983,6 +983,7 @@ static int copy_mount_options (const void * data, unsigned long *where)
        if (!data)
                return 0;
 
+#if 0
        vma = find_vma(current->mm, (unsigned long) data);
        if (!vma || (unsigned long) data < vma->vm_start)
                return -EFAULT;
@@ -991,10 +992,13 @@ static int copy_mount_options (const void * data, unsigned long *where)
        i = vma->vm_end - (unsigned long) data;
        if (PAGE_SIZE <= (unsigned long) i)
                i = PAGE_SIZE-1;
-       if (!(page = __get_free_page(GFP_KERNEL))) {
+#else
+       i = PAGE_SIZE;          
+#endif         
+       if (!(page = get_free_page(GFP_KERNEL))) {
                return -ENOMEM;
        }
-       if (copy_from_user((void *) page,data,i)) {
+       if (copy_from_user((void *) page,data,i) == i) {
                free_page(page); 
                return -EFAULT;
        }
index 7e94bfd1c8acc3e0b4c58409a698d6e278ea4837..ccbb17dce079bd051e109c0a3c719964087b8e76 100644 (file)
@@ -111,7 +111,7 @@ static long long ufs_file_lseek(
                if (offset != file->f_pos) {
                        file->f_pos = offset;
                        file->f_reada = 0;
-                       file->f_version = ++event;
+                       file->f_version = ++global_event;
                }
                retval = offset;
        }
index 84e003d2d294ecb20c70db7ea0f531ea8f451c62..c22297f6507aa5771f65320e57d559d598cdb3bc 100644 (file)
@@ -509,7 +509,7 @@ void ufs_read_inode (struct inode * inode)
        inode->i_mtime = SWAB32(ufs_inode->ui_mtime.tv_sec);
        inode->i_blocks = SWAB32(ufs_inode->ui_blocks);
        inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat) */
-       inode->i_version = ++event;
+       inode->i_version = ++global_event;
 
        inode->u.ufs_i.i_flags = SWAB32(ufs_inode->ui_flags);
        inode->u.ufs_i.i_gen = SWAB32(ufs_inode->ui_gen);
index 3daf77c57042d10e86f7773730c37e033b20b39b..8bce6f8e8c62169860e5738e0cb4c17abdf25d52 100644 (file)
@@ -330,7 +330,7 @@ static struct buffer_head * ufs_add_entry (struct inode * dir,
                         */
                        dir->i_mtime = dir->i_ctime = CURRENT_TIME;
                        mark_inode_dirty(dir);
-                       dir->i_version = ++event;
+                       dir->i_version = ++global_event;
                        mark_buffer_dirty(bh, 1);
                        *res_dir = de;
                        *err = 0;
@@ -435,7 +435,7 @@ int ufs_create (struct inode * dir, struct dentry * dentry, int mode)
        }
        de->d_ino = SWAB32(inode->i_ino);
        ufs_set_de_type (de, inode->i_mode);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -485,7 +485,7 @@ int ufs_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
                goto out_no_entry;
        de->d_ino = SWAB32(inode->i_ino);
        ufs_set_de_type (de, inode->i_mode);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -559,7 +559,7 @@ int ufs_mkdir(struct inode * dir, struct dentry * dentry, int mode)
                goto out_no_entry;
        de->d_ino = SWAB32(inode->i_ino);
        ufs_set_de_type (de, inode->i_mode);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -672,7 +672,7 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry)
                goto end_rmdir;
 
        retval = ufs_delete_entry (dir, de, bh);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        if (retval)
                goto end_rmdir;
        mark_buffer_dirty(bh, 1);
@@ -684,7 +684,7 @@ int ufs_rmdir (struct inode * dir, struct dentry *dentry)
                ufs_warning (inode->i_sb, "ufs_rmdir",
                              "empty directory has nlink!=2 (%d)",
                              inode->i_nlink);
-       inode->i_version = ++event;
+       inode->i_version = ++global_event;
        inode->i_nlink = 0;
        inode->i_size = 0;
        mark_inode_dirty(inode);
@@ -736,7 +736,7 @@ int ufs_unlink(struct inode * dir, struct dentry *dentry)
        retval = ufs_delete_entry (dir, de, bh);
        if (retval)
                goto end_unlink;
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -817,7 +817,7 @@ int ufs_symlink (struct inode * dir, struct dentry * dentry,
        if (!bh)
                goto out_no_entry;
        de->d_ino = SWAB32(inode->i_ino);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -861,7 +861,7 @@ int ufs_link (struct dentry * old_dentry, struct inode * dir,
                return err;
 
        de->d_ino = SWAB32(inode->i_ino);
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        mark_buffer_dirty(bh, 1);
        if (IS_SYNC(dir)) {
                ll_rw_block (WRITE, 1, &bh);
@@ -949,7 +949,7 @@ int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
                                         &retval);
        if (!new_bh)
                goto end_rename;
-       new_dir->i_version = ++event;
+       new_dir->i_version = ++global_event;
 
        /*
         * ok, that's it
@@ -957,7 +957,7 @@ int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
        new_de->d_ino = SWAB32(old_inode->i_ino);
        ufs_delete_entry (old_dir, old_de, old_bh);
 
-       old_dir->i_version = ++event;
+       old_dir->i_version = ++global_event;
        if (new_inode) {
                new_inode->i_nlink--;
                new_inode->i_ctime = CURRENT_TIME;
index 392aa8ad306189fcfa9c4b2f6152742e9ebf473f..64467ba083661c337b0131c8254954fba146bc3a 100644 (file)
@@ -975,8 +975,8 @@ int vfat_create(struct inode *dir,struct dentry* dentry,int mode)
                return res;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        mark_inode_dirty(inode);
-       inode->i_version = ++event;
-       dir->i_version = event;
+       inode->i_version = ++global_event;
+       dir->i_version = global_event;
        MSDOS_I(dir)->i_last_pos = 0;
        dentry->d_time = dentry->d_parent->d_inode->i_version;
        d_instantiate(dentry,inode);
@@ -1022,7 +1022,7 @@ static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
        /* remove the shortname */
        dir->i_mtime = CURRENT_TIME;
        dir->i_atime = CURRENT_TIME;
-       dir->i_version = ++event;
+       dir->i_version = ++global_event;
        MSDOS_I(dir)->i_last_pos = 0;
        mark_inode_dirty(dir);
        de->name[0] = DELETED_FLAG;
@@ -1108,8 +1108,8 @@ int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode)
                goto out;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        mark_inode_dirty(inode);
-       inode->i_version = ++event;
-       dir->i_version = event;
+       inode->i_version = ++global_event;
+       dir->i_version = global_event;
        MSDOS_I(dir)->i_last_pos = 0;
        dir->i_nlink++;
        inode->i_nlink = 2; /* no need to mark them dirty */
@@ -1181,7 +1181,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
                if (res < 0) goto rename_done;
        }
 
-       new_dir->i_version = ++event;
+       new_dir->i_version = ++global_event;
        MSDOS_I(new_dir)->i_last_pos = 0;
 
        /* releases old_bh */
@@ -1191,7 +1191,7 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
        fat_attach(old_inode, sinfo.ino);
        mark_inode_dirty(old_inode);
 
-       old_dir->i_version = ++event;
+       old_dir->i_version = ++global_event;
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
        mark_inode_dirty(old_dir);
        if (new_inode) {
index c44917b8023c406dcb37dcfc2f626aaa6e29340d..9c1f8b5f1169b065785905dd1d373ec9b7b23373 100644 (file)
@@ -151,6 +151,9 @@ extern struct dentry * d_alloc_root(struct inode * root_inode, struct dentry * o
 /* test whether root is busy without destroying dcache */
 extern int is_root_busy(struct dentry *);
 
+/* test whether we have any submounts in a subdir tree */
+extern int have_submounts(struct dentry *);
+
 /*
  * This adds the entry to the hash queues.
  */
index 4a16756d9623767f0939fdd55402fa826d51de2e..48d79561f879d4f8b09ca649c8a3ff6e18b53dd9 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef _LINUX_ERRQUEUE_H
 #define _LINUX_ERRQUEUE_H 1
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 
 struct sock_extended_err
 {
index cd5f3139164e8656009570bec524c54248fa64b5..c95f372c4ab6ac1f6a428f2feb6de0cbd238175b 100644 (file)
 #define IFF_AUTOMEDIA  0x4000          /* auto media select active     */
 #define IFF_DYNAMIC    0x8000          /* dialup device with changing addresses*/
 
-#ifdef __KERNEL__
-/*
- * The ifaddr structure contains information about one address
- * of an interface.  They are maintained by the different address
- * families, are allocated and attached when an address is set,
- * and are linked together so all addresses for an interface can
- * be located.
- */
-struct ifaddr 
-{
-       struct sockaddr ifa_addr;       /* address of interface         */
-       union {
-               struct sockaddr ifu_broadaddr;
-               struct sockaddr ifu_dstaddr;
-       } ifa_ifu;
-       struct iface            *ifa_ifp;       /* back-pointer to interface    */
-       struct ifaddr           *ifa_next;      /* next address for interface   */
-};
-
-#define        ifa_broadaddr   ifa_ifu.ifu_broadaddr   /* broadcast address    */
-#define        ifa_dstaddr     ifa_ifu.ifu_dstaddr     /* other end of link    */
-
-#endif /* __KERNEL__ */ 
-
 /*
  *     Device mapping structure. I'd just gone off and designed a 
  *     beautiful scheme using only loadable modules with arguments
index 25c4495980f8a68b52eb86de66aad54eec2d836d..323a305c46abd52766568c63595b1a68004dfa00 100644 (file)
@@ -16,6 +16,7 @@ struct ipv4_devconf
        int     log_martians;
        int     forwarding;
        int     mc_forwarding;
+       int     hidden;
        void    *sysctl;
 };
 
@@ -40,6 +41,7 @@ struct in_device
 
 #define IN_DEV_LOG_MARTIANS(in_dev)    (ipv4_devconf.log_martians || (in_dev)->cnf.log_martians)
 #define IN_DEV_PROXY_ARP(in_dev)       (ipv4_devconf.proxy_arp || (in_dev)->cnf.proxy_arp)
+#define IN_DEV_HIDDEN(in_dev)          ((in_dev)->cnf.hidden && ipv4_devconf.hidden)
 #define IN_DEV_SHARED_MEDIA(in_dev)    (ipv4_devconf.shared_media || (in_dev)->cnf.shared_media)
 #define IN_DEV_TX_REDIRECTS(in_dev)    (ipv4_devconf.send_redirects || (in_dev)->cnf.send_redirects)
 #define IN_DEV_SEC_REDIRECTS(in_dev)   (ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects)
index 6675cee9582ee5895572d706b51a1baee65a4a2e..7b642728ae9e1f94c413b690c9af06790dafa478 100644 (file)
@@ -88,6 +88,8 @@
 #define        IPOPT_TS_TSANDADDR      1               /* timestamps and addresses */
 #define        IPOPT_TS_PRESPEC        3               /* specified modules only */
 
+#ifdef __KERNEL__
+
 struct ip_options {
   __u32                faddr;                          /* Saved first hop address */
   unsigned char        optlen;
@@ -108,7 +110,6 @@ struct ip_options {
   unsigned char __data[0];
 };
 
-#ifdef __KERNEL__
 #define optlength(opt) (sizeof(struct ip_options) + opt->optlen)
 #endif
 
index 2acec5295f43aa54f841c17e02e369ca0a8942ed..86f84a90a91c3267b0957df768fef82f073f4dd5 100644 (file)
@@ -24,7 +24,9 @@
 #ifndef _LINUX_NETDEVICE_H
 #define _LINUX_NETDEVICE_H
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 #include <linux/if.h>
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
index b339f6528d8396f12507fbe2dc13206ee2edc702..39802a5f8c20f9ceaef6c620e3d78586b41cb19d 100644 (file)
@@ -1,7 +1,9 @@
 #ifndef __LINUX_RTNETLINK_H
 #define __LINUX_RTNETLINK_H
 
+#ifdef __KERNEL__
 #include <linux/config.h>
+#endif
 #include <linux/netlink.h>
 
 #define RTNL_DEBUG 1
index 446866db150eb44e3c43a10a64982ec0c1eecf64..d983c17ebf1dcf2702b7869c18131741884476c1 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <asm/param.h> /* for HZ */
 
-extern unsigned long event;
+extern unsigned long global_event;
 
 #include <linux/binfmts.h>
 #include <linux/personality.h>
index d681aa5ba9ba0c8d3b54d43e4368afe7f00670a5..837a3e4659ea96bf847dd161260323b0a58e7717 100644 (file)
@@ -106,7 +106,7 @@ __KINLINE struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size,
 
        __ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) +  CMSG_ALIGN(__cmsg->cmsg_len));
        if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size)
-               return NULL;
+               return (struct cmsghdr*)0;
 
        return __ptr;
 }
index e675d9b2aa2459041e8581b469098f47d97abd5f..00bebabefd75929efc0e41163166e975cfbf99a9 100644 (file)
@@ -268,7 +268,8 @@ enum
        NET_IPV4_CONF_RP_FILTER=8,
        NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9,
        NET_IPV4_CONF_BOOTP_RELAY=10,
-       NET_IPV4_CONF_LOG_MARTIANS=11
+       NET_IPV4_CONF_LOG_MARTIANS=11,
+       NET_IPV4_CONF_HIDDEN=12
 };
 
 /* /proc/sys/net/ipv6 */
index c8a87b6ff6401d06ba8a1a7c126a514d121f4bf2..e0838cd20bd3865d32c6558a1798ff5d0fc4a8f8 100644 (file)
@@ -140,6 +140,7 @@ EXPORT_SYMBOL(d_instantiate);
 EXPORT_SYMBOL(d_alloc);
 EXPORT_SYMBOL(d_lookup);
 EXPORT_SYMBOL(d_path);
+EXPORT_SYMBOL(have_submounts);
 EXPORT_SYMBOL(__mark_inode_dirty);
 EXPORT_SYMBOL(get_empty_filp);
 EXPORT_SYMBOL(init_private_file);
@@ -385,7 +386,7 @@ EXPORT_SYMBOL(insert_inode_hash);
 EXPORT_SYMBOL(remove_inode_hash);
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
-EXPORT_SYMBOL(event);
+EXPORT_SYMBOL(global_event);
 EXPORT_SYMBOL(__down);
 EXPORT_SYMBOL(__down_interruptible);
 EXPORT_SYMBOL(__down_trylock);
index ecd36cd27dcd3a3c9308e38b1307436534cec95d..4c2f4a9ef696ad07b10d38236f0c5ebcccb6ac27 100644 (file)
@@ -78,7 +78,7 @@ long time_reftime = 0;                /* time at last adjustment (s) */
 long time_adjust = 0;
 long time_adjust_step = 0;
 
-unsigned long event = 0;
+unsigned long global_event = 0;
 
 extern int do_setitimer(int, struct itimerval *, struct itimerval *);
 unsigned int * prof_buffer = NULL;
index f150a052cac73a2a6352351251241557838c9b08..338baba8766491d4f9caf584c4563120c15b5e4d 100644 (file)
@@ -53,6 +53,7 @@ static int try_to_swap_out(struct task_struct * tsk, struct vm_area_struct* vma,
                 * tables to the global page map.
                 */
                set_pte(page_table, pte_mkold(pte));
+               flush_tlb_page(vma, address);
                set_bit(PG_referenced, &page_map->flags);
                return 0;
        }
@@ -95,6 +96,7 @@ drop_pte:
         * some real work in the future in "shrink_mmap()".
         */
        if (!pte_dirty(pte)) {
+               flush_cache_page(vma, address);
                pte_clear(page_table);
                goto drop_pte;
        }
index 18dc9c766c8a94dae025332f758d3b59fb1ae9fe..9e04da2d4fe9c38f21386789c3085245da86a971 100644 (file)
@@ -1266,7 +1266,6 @@ static int ax25_accept(struct socket *sock, struct socket *newsock, int flags)
        newsk->sleep = &newsock->wait;
 
        /* Now attach up the new socket */
-       skb->destructor = NULL;
        kfree_skb(skb);
        sk->ack_backlog--;
        newsock->sk    = newsk;
index 6a2fd63588014b296bea00f7c3c0e82f51bff1ff..aac8a9260d24fbd18a25a60cbab160ec932970e5 100644 (file)
@@ -2655,7 +2655,7 @@ static int brg_rx(struct sk_buff *skb, int port)
         */
        if(clone) {
          struct sk_buff *skb2 = skb;
-         skb = skb_clone(skb2, GFP_KERNEL);
+         skb = skb_clone(skb2, GFP_ATOMIC);
          if (skb == NULL) {
            return(0);
          }
index 79e738126407242e15d797b576b79cb23ba8ed87..d81c1beeb93934fcc43e204abe7306e030ca128f 100644 (file)
@@ -65,6 +65,8 @@
  *                                     clean up the APFDDI & gen. FDDI bits.
  *             Alexey Kuznetsov:       new arp state machine;
  *                                     now it is in net/core/neighbour.c.
+ *             Julian Anastasov:       "hidden" flag: hide the
+ *                                     interface and don't reply for it
  */
 
 /* RFC1122 Status:
@@ -308,10 +310,15 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb)
        u32 saddr;
        u8  *dst_ha = NULL;
        struct device *dev = neigh->dev;
+       struct device *dev2;
+       struct in_device *in_dev2;
        u32 target = *(u32*)neigh->primary_key;
        int probes = neigh->probes;
 
-       if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL)
+       if (skb &&
+           (dev2 = ip_dev_find(skb->nh.iph->saddr)) != NULL &&
+           (in_dev2 = dev2->ip_ptr) != NULL &&
+           !IN_DEV_HIDDEN(in_dev2))
                saddr = skb->nh.iph->saddr;
        else
                saddr = inet_select_addr(dev, target, RT_SCOPE_LINK);
@@ -653,8 +660,14 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
 
        /* Special case: IPv4 duplicate address detection packet (RFC2131) */
        if (sip == 0) {
+               struct device *dev2;
+               struct in_device *in_dev2;
+
                if (arp->ar_op == __constant_htons(ARPOP_REQUEST) &&
-                   inet_addr_type(tip) == RTN_LOCAL)
+                   (dev2 = ip_dev_find(tip)) != NULL &&
+                   (dev2 == dev ||
+                    ((in_dev2 = dev2->ip_ptr) != NULL &&
+                     !IN_DEV_HIDDEN(in_dev2))))
                        arp_send(ARPOP_REPLY,ETH_P_ARP,tip,dev,tip,sha,dev->dev_addr,dev->dev_addr);
                goto out;
        }
@@ -668,6 +681,20 @@ int arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
                if (addr_type == RTN_LOCAL) {
                        n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
                        if (n) {
+                               if (ipv4_devconf.hidden &&
+                                   skb->pkt_type != PACKET_HOST) {
+                                       struct device *dev2;
+                                       struct in_device *in_dev2;
+
+                                       if ((dev2 = ip_dev_find(tip)) != NULL &&
+                                           dev2 != dev &&
+                                           (in_dev2 = dev2->ip_ptr) != NULL &&
+                                           IN_DEV_HIDDEN(in_dev2)) {
+                                               neigh_release(n);
+                                               goto out;
+                                       }
+                               }
+
                                arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha);
                                neigh_release(n);
                        }
index a50ee3bd573d0f495e596c284de8a277880488da..41b42a52f0b91be5f162b70ca3f141fb8dafcfdc 100644 (file)
@@ -658,7 +658,7 @@ u32 inet_select_addr(struct device *dev, u32 dst, int scope)
                        addr = ifa->ifa_local;
        } endfor_ifa(in_dev);
        
-       if (addr || scope >= RT_SCOPE_LINK)
+       if (addr)
                return addr;
 
        /* Not loopback addresses on loopback should be preferred
@@ -670,7 +670,9 @@ u32 inet_select_addr(struct device *dev, u32 dst, int scope)
                        continue;
 
                for_primary_ifa(in_dev) {
-                       if (ifa->ifa_scope <= scope)
+                       if (!IN_DEV_HIDDEN(in_dev) &&
+                           ifa->ifa_scope <= scope &&
+                           ifa->ifa_scope != RT_SCOPE_LINK)
                                return ifa->ifa_local;
                } endfor_ifa(in_dev);
        }
@@ -923,7 +925,7 @@ int devinet_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
 static struct devinet_sysctl_table
 {
        struct ctl_table_header *sysctl_header;
-       ctl_table devinet_vars[12];
+       ctl_table devinet_vars[13];
        ctl_table devinet_dev[2];
        ctl_table devinet_conf_dir[2];
        ctl_table devinet_proto_dir[2];
@@ -963,6 +965,9 @@ static struct devinet_sysctl_table
         {NET_IPV4_CONF_LOG_MARTIANS, "log_martians",
          &ipv4_devconf.log_martians, sizeof(int), 0644, NULL,
          &proc_dointvec},
+       {NET_IPV4_CONF_HIDDEN, "hidden",
+         &ipv4_devconf.hidden, sizeof(int), 0644, NULL,
+         &proc_dointvec},
         {0}},
 
        {{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, devinet_sysctl.devinet_vars},{0}},
index a52e7ed7a5d33f88abba7ef4722cbb67518a952a..f7d5db426daf02f450bf92c11b45669cebea7c72 100644 (file)
@@ -842,6 +842,7 @@ static void masq_expire(unsigned long data)
         */
        if (atomic_read(&ms->refcnt) == 1) {
                kfree_s(ms,sizeof(*ms));
+               sysctl_ip_always_defrag--;
                MOD_DEC_USE_COUNT;
                goto masq_expire_out;
        }
index 7fa0f0b2121afb602f1b7891c2be47006006b97b..65f1129c61a5dbb35dac610053c44c98913bbc4f 100644 (file)
@@ -570,6 +570,21 @@ static int ipv6_generate_eui64(u8 *eui, struct device *dev)
        }
        return -1;
 }
+
+static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
+{
+       int err = -1;
+       struct inet6_ifaddr *ifp;
+
+       for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
+               if (ifp->scope == IFA_LINK && !(ifp->flags&(ADDR_STATUS|DAD_STATUS))) {
+                       memcpy(eui, ifp->addr.s6_addr+8, 8);
+                       err = 0;
+                       break;
+               }
+       }
+       return err;
+}
 #endif
 
 /*
@@ -742,7 +757,8 @@ void addrconf_prefix_rcv(struct device *dev, u8 *opt, int len)
 #ifdef CONFIG_IPV6_EUI64
                if (pinfo->prefix_len == 64) {
                        memcpy(&addr, &pinfo->prefix, 8);
-                       if (ipv6_generate_eui64(addr.s6_addr + 8, dev))
+                       if (ipv6_generate_eui64(addr.s6_addr + 8, dev) &&
+                           ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev))
                                return;
                        goto ok;
                }
@@ -1374,7 +1390,7 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)
         */
 
        if (ifp->idev->cnf.forwarding == 0 &&
-           (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) == 0 &&
+           (dev->flags&IFF_LOOPBACK) == 0 &&
            (ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
                struct in6_addr all_routers;