## Automatically generated incremental diff
## From:   linux-2.2.15-pre6
## To:     linux-2.2.15-pre7
## Robot:  $Id: make-incremental-diff,v 1.7 2001/12/04 05:19:54 hpa Exp $

diff -urN linux-2.2.15-pre6/Documentation/sound/Maestro linux/Documentation/sound/Maestro
--- linux-2.2.15-pre6/Documentation/sound/Maestro	Tue Jan  4 10:12:10 2000
+++ linux/Documentation/sound/Maestro	Mon Dec  3 21:59:03 2001
@@ -24,7 +24,7 @@
 
 The various families of Maestro are mostly identical as far as this 
 driver is concerned.  It doesn't touch the DSP parts that differ (though
-it could for FM synthesis)
+it could for FM synthesis).
 
 Driver OSS Behavior
 --------------------
@@ -91,8 +91,33 @@
 ( dsps_order=2 ).  These devices act as fully distinct units and use
 separate channels in the maestro.
 
+Power Management
+----------------
+
+As of version 0.14, this driver has a minimal understanding of PCI
+Power Management.  If it finds a valid power management capability
+on the PCI device it will attempt to use the power management
+functions of the maestro.  It will only do this on Maestro 2Es and
+only on machines that are known to function well.  You can
+force the use of power management by setting the 'use_pm' module
+option to 1, or can disable it entirely by setting it to 0.
+
+When using power management, the driver does a few things
+differently.  It will keep the chip in a lower power mode
+when the module is inserted but /dev/dsp is not open.  This
+allows the mixer to function but turns off the clocks
+on other parts of the chip.  When /dev/dsp is opened the chip
+is brought into full power mode, and brought back down
+when it is closed.  It also powers down the chip entirely
+when the module is removed or the machine is shutdown.  This
+can have nonobvious consequences.  CD audio may not work
+after a power managing driver is removed.  Also, software that
+doesn't understand power management may not be able to talk
+to the powered down chip until the machine goes through a hard
+reboot to bring it back.
+
 .. more details ..
------------------
+------------------
 
 drivers/sound/maestro.c contains comments that hopefully explain
 the maestro implementation.
diff -urN linux-2.2.15-pre6/MAINTAINERS linux/MAINTAINERS
--- linux-2.2.15-pre6/MAINTAINERS	Mon Dec  3 21:58:57 2001
+++ linux/MAINTAINERS	Mon Dec  3 21:59:03 2001
@@ -463,6 +463,12 @@
 W:	http://www.suse.cz/development/joystick/
 S:	Maintained
 
+KCTT DRIVER FOR ANTENNA ROTORS
+P:	Jean-Paul Roubelat
+M:	jpr@f6fbb.org
+L:	linux-hams@vger.rutgers.edu
+S:	Maintained
+
 KERNEL AUTOMOUNTER (AUTOFS)
 P:	H. Peter Anvin
 M:	hpa@zytor.com
@@ -714,8 +720,8 @@
 S:	Maintained
 
 ROSE NETWORK LAYER
-P:	Frederic Rible
-M:	frible@teaser.fr
+P:	Jean-Paul Roubelat
+M:	jpr@f6fbb.org
 L:	linux-hams@vger.rutgers.edu
 S:	Maintained
 
@@ -920,6 +926,12 @@
 P:	Henner Eisen
 M:	eis@baty.hanse.de
 L:	linux-x25@vger.rutgers.edu
+S:	Maintained
+
+YAM DRIVER FOR AX.25
+P:	Jean-Paul Roubelat
+M:	jpr@f6fbb.org
+L:	linux-hams@vger.rutgers.edu
 S:	Maintained
 
 Z85230 SYNCHRONOUS DRIVER
diff -urN linux-2.2.15-pre6/Makefile linux/Makefile
--- linux-2.2.15-pre6/Makefile	Mon Dec  3 21:58:57 2001
+++ linux/Makefile	Mon Dec  3 21:59:03 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 15
-EXTRAVERSION = pre6
+EXTRAVERSION = pre7
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.15-pre6/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- linux-2.2.15-pre6/arch/i386/kernel/io_apic.c	Tue Jan  4 10:12:11 2000
+++ linux/arch/i386/kernel/io_apic.c	Mon Dec  3 21:59:03 2001
@@ -1277,6 +1277,37 @@
 	}
 }
 
+/* Patch to set the IO-APIC physical IDs based on the values stored in the MPC table */
+/* by Matt Domsch <Matt_Domsch@dell.com>  Tue Dec 21 12:25:05 CST 1999 */
+
+static void __init setup_ioapic_ids_from_mpc(void)
+{
+	struct IO_APIC_reg_00 reg_00;
+	/*
+	 * Set the IOAPIC ID to the value stored in the MPC table.
+	 */
+	int apic;
+	for (apic = 0; apic < mp_apic_entries; apic++) {
+		/* Read the register 0 value */
+		*(int *)&reg_00 = io_apic_read(apic, 0);
+		
+		if(reg_00.ID != mp_apics[apic].mpc_apicid) {
+			/* Change the value */
+			printk("...changing IO-APIC physical APIC ID to %d\n", mp_apics[apic].mpc_apicid);
+			reg_00.ID = mp_apics[apic].mpc_apicid;
+			io_apic_write(apic, 0, *(int *)&reg_00);
+
+			/*
+			 * Sanity check
+			 */
+			*(int *)&reg_00 = io_apic_read(apic, 0);
+			if (reg_00.ID != mp_apics[apic].mpc_apicid)
+				panic("could not set ID");
+		}
+	}
+}
+
+
 /*
  *
  * IRQ's that are handled by the old PIC in all cases:
@@ -1336,9 +1367,11 @@
 	 * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS
 	 * mptable:
 	 */
+	setup_ioapic_ids_from_mpc();
 	setup_IO_APIC_irqs();
 	init_IO_APIC_traps();
 	check_timer();
 
 	print_IO_APIC();
 }
+
diff -urN linux-2.2.15-pre6/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
--- linux-2.2.15-pre6/arch/i386/kernel/setup.c	Mon Dec  3 21:58:57 2001
+++ linux/arch/i386/kernel/setup.c	Mon Dec  3 21:59:03 2001
@@ -436,14 +436,14 @@
 
 __initfunc(static int get_model_name(struct cpuinfo_x86 *c))
 {
-	unsigned int n, dummy, *v;
+	unsigned int n, dummy, *v, ecx, edx;
 
 	/* Actually we must have cpuid or we could never have
 	 * figured out that this was AMD from the vendor info :-).
 	 */
 
 	cpuid(0x80000000, &n, &dummy, &dummy, &dummy);
-	if (n < 4)
+	if (n < 0x80000004)
 		return 0;
 	cpuid(0x80000001, &dummy, &dummy, &dummy, &(c->x86_capability));
 	v = (unsigned int *) c->x86_model_id;
@@ -459,6 +459,18 @@
 	    (boot_cpu_data.x86_mask >= 8)))
 		c->x86_capability |= X86_FEATURE_MTRR;
 
+	if (n >= 0x80000005){
+		cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
+		printk("CPU: L1 I Cache: %dK  L1 D Cache: %dK\n",
+			ecx>>24, edx>>24);
+		c->x86_cache_size=(ecx>>24)+(edx>>24);
+	}
+	if (n >= 0x80000006){
+		cpuid(0x80000006, &dummy, &dummy, &ecx, &edx);
+		printk("CPU: L2 Cache: %dK\n", ecx>>16);
+		c->x86_cache_size = ecx>>16;
+	}
+
 	return 1;
 }
 
@@ -529,14 +541,6 @@
 			break;
 		case 6:	/* An Athlon. We can trust the BIOS probably */
 		{
-			
-			u32 ecx, edx, dummy;
-			cpuid(0x80000005, &dummy, &dummy, &ecx, &edx);
-			printk("L1 I Cache: %dK  L1 D Cache: %dK\n",
-				ecx>>24, edx>>24);
-			cpuid(0x80000006, &dummy, &dummy, &ecx, &edx);
-			printk("L2 Cache: %dK\n", ecx>>16);
-			c->x86_cache_size = ecx>>16;
 			break;
 		}
 		
diff -urN linux-2.2.15-pre6/drivers/net/Makefile linux/drivers/net/Makefile
--- linux-2.2.15-pre6/drivers/net/Makefile	Mon Dec  3 21:58:58 2001
+++ linux/drivers/net/Makefile	Mon Dec  3 21:59:03 2001
@@ -864,7 +864,6 @@
   ifeq ($(CONFIG_LANMEDIA),m)
   CONFIG_SYNCPPP_MODULE = y
   MOD_IN_SUB_DIRS += lmc
-  M_OBJS += lmc.o
   endif
 endif
 
diff -urN linux-2.2.15-pre6/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c
--- linux-2.2.15-pre6/drivers/scsi/scsi.c	Mon Dec  3 21:58:58 2001
+++ linux/drivers/scsi/scsi.c	Mon Dec  3 21:59:04 2001
@@ -277,6 +277,7 @@
 {"HP", "C2500A", "", BLIST_NOLUN},              /* scanjet iicx */
 {"YAMAHA","CDR100","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
 {"YAMAHA","CDR102","1.00", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
+{"YAMAHA","CRW8424S","1.0", BLIST_NOLUN},	/* Locks up if polled for lun != 0 */
 {"RELISYS", "Scorpio", "*", BLIST_NOLUN},	/* responds to all LUN */
 
 /*
diff -urN linux-2.2.15-pre6/drivers/scsi/st.c linux/drivers/scsi/st.c
--- linux-2.2.15-pre6/drivers/scsi/st.c	Sat May 22 14:51:26 1999
+++ linux/drivers/scsi/st.c	Mon Dec  3 21:59:04 2001
@@ -8,10 +8,10 @@
   order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
   Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
 
-  Copyright 1992 - 1999 Kai Makisara
+  Copyright 1992 - 2000 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Tue May 18 09:29:52 1999 by makisara@home
+  Last modified: Wed Feb  2 22:04:05 2000 by makisara@kai.makisara.local
   Some small formal changes - aeb, 950809
 */
 
@@ -595,8 +595,14 @@
 #endif
       return (-EBUSY);
     }
+    STp->in_use = 1;
     STp->rew_at_close = (MINOR(inode->i_rdev) & 0x80) == 0;
 
+    if (scsi_tapes[dev].device->host->hostt->module)
+	__MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+    if(st_template.module)
+	__MOD_INC_USE_COUNT(st_template.module);
+
     if (mode != STp->current_mode) {
 #if DEBUG
       if (debugging)
@@ -618,6 +624,11 @@
       STp->buffer = new_tape_buffer(FALSE, need_dma_buffer);
       if (STp->buffer == NULL) {
 	printk(KERN_WARNING "st%d: Can't allocate tape buffer.\n", dev);
+	STp->in_use = 0;
+	if (scsi_tapes[dev].device->host->hostt->module)
+	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
+	if(st_template.module)
+	    __MOD_DEC_USE_COUNT(st_template.module);
 	return (-EBUSY);
       }
     }
@@ -651,17 +662,15 @@
     STp->nbr_waits = STp->nbr_finished = 0;
 #endif
 
-    if (scsi_tapes[dev].device->host->hostt->module)
-	__MOD_INC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
-    if(st_template.module)
-	__MOD_INC_USE_COUNT(st_template.module);
-
     memset ((void *) &cmd[0], 0, 10);
     cmd[0] = TEST_UNIT_READY;
 
     SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
 		       TRUE);
     if (!SCpnt) {
+	(STp->buffer)->in_use = 0;
+	STp->buffer = NULL;
+	STp->in_use = 0;
 	if (scsi_tapes[dev].device->host->hostt->module)
 	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
 	if(st_template.module)
@@ -671,11 +680,16 @@
 
     if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
 	(SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
-      memset ((void *) &cmd[0], 0, 10);
-      cmd[0] = TEST_UNIT_READY;
 
-      SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
-			 TRUE);
+      for (i=0; i < 10; i++) {
+	  memset ((void *) &cmd[0], 0, 10);
+	  cmd[0] = TEST_UNIT_READY;
+	  SCpnt = st_do_scsi(SCpnt, STp, cmd, 0, STp->long_timeout, MAX_READY_RETRIES,
+			     TRUE);
+	  if ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
+	      (SCpnt->sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
+	      break;
+      }
 
       (STp->device)->was_reset = 0;
       STp->partition = STp->new_partition = 0;
@@ -709,7 +723,6 @@
       STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
       STp->partition = STp->new_partition = 0;
       STp->door_locked = ST_UNLOCKED;
-      STp->in_use = 1;
       return 0;
     }
 
@@ -787,6 +800,7 @@
 	scsi_release_command(SCpnt);
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
+	STp->in_use = 0;
 	if (scsi_tapes[dev].device->host->hostt->module)
 	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
 	if(st_template.module)
@@ -820,6 +834,7 @@
       if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
+	STp->in_use = 0;
 	if (scsi_tapes[dev].device->host->hostt->module)
 	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
 	if(st_template.module)
@@ -837,13 +852,15 @@
 	printk(ST_DEB_MSG "st%d: Updating partition number in status.\n", dev);
 #endif
       if ((STp->partition = find_partition(inode)) < 0) {
+	i = STp->partition;
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
+	STp->in_use = 0;
 	if (scsi_tapes[dev].device->host->hostt->module)
 	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
 	if(st_template.module)
 	    __MOD_DEC_USE_COUNT(st_template.module);
-	return STp->partition;
+	return i;
       }
       STp->new_partition = STp->partition;
       STp->nbr_partitions = 1;  /* This guess will be updated when necessary */
@@ -856,6 +873,7 @@
 	  (i = set_mode_densblk(inode, STp, STm)) < 0) {
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
+	STp->in_use = 0;
 	if (scsi_tapes[dev].device->host->hostt->module)
 	    __MOD_DEC_USE_COUNT(scsi_tapes[dev].device->host->hostt->module);
 	if(st_template.module)
@@ -869,8 +887,6 @@
       }
     }
 
-    STp->in_use = 1;
-
     return 0;
 }
 
@@ -898,19 +914,25 @@
     STm = &(STp->modes[STp->current_mode]);
     STps = &(STp->ps[STp->partition]);
 
+    if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+      result = flush_write_buffer(STp);
+      if (result != 0 && result != (-ENOSPC))
+	  goto out;
+    }
+
     if (STp->can_partitions &&
-	(result = update_partition(inode)) < 0) {
+	(result2 = update_partition(inode)) < 0) {
 #if DEBUG
       if (debugging)
 	printk(ST_DEB_MSG "st%d: update_partition at close failed.\n", dev);
 #endif
+      if (result == 0)
+	  result = result2;
       goto out;
     }
 
     if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) {
 
-      result = flush_write_buffer(STp);
-
 #if DEBUG
       if (debugging) {
 	printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
@@ -920,41 +942,38 @@
       }
 #endif
 
-      if (result == 0 || result == (-ENOSPC)) {
+      memset(cmd, 0, 10);
+      cmd[0] = WRITE_FILEMARKS;
+      cmd[4] = 1 + STp->two_fm;
 
-	memset(cmd, 0, 10);
-	cmd[0] = WRITE_FILEMARKS;
-	cmd[4] = 1 + STp->two_fm;
-
-	SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES,
-			   TRUE);
-	if (!SCpnt)
+      SCpnt = st_do_scsi(NULL, STp, cmd, 0, STp->timeout, MAX_WRITE_RETRIES,
+			 TRUE);
+      if (!SCpnt)
 	  goto out;
 
-	if ((STp->buffer)->last_result_fatal != 0 &&
-	    ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
-	     (SCpnt->sense_buffer[2] & 0x4f) != 0x40 ||
-	     ((SCpnt->sense_buffer[0] & 0x80) != 0 &&
-	      (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] |
-	       SCpnt->sense_buffer[5] |
-	       SCpnt->sense_buffer[6]) == 0))) {
-	    /* Filter out successful write at EOM */
-	    scsi_release_command(SCpnt);
-	    SCpnt = NULL;
-	    printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
-	    if (result == 0)
-		result = (-EIO);
-	}
-	else {
+      if ((STp->buffer)->last_result_fatal != 0 &&
+	  ((SCpnt->sense_buffer[0] & 0x70) != 0x70 ||
+	   (SCpnt->sense_buffer[2] & 0x4f) != 0x40 ||
+	   ((SCpnt->sense_buffer[0] & 0x80) != 0 &&
+	    (SCpnt->sense_buffer[3] | SCpnt->sense_buffer[4] |
+	     SCpnt->sense_buffer[5] |
+	     SCpnt->sense_buffer[6]) == 0))) {
+	  /* Filter out successful write at EOM */
+	  scsi_release_command(SCpnt);
+	  SCpnt = NULL;
+	  printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
+	  if (result == 0)
+	      result = (-EIO);
+      }
+      else {
 	  scsi_release_command(SCpnt);
 	  SCpnt = NULL;
 	  if (STps->drv_file >= 0)
 	      STps->drv_file++ ;
 	  STps->drv_block = 0;
 	  if (STp->two_fm)
-	    cross_eof(STp, FALSE);
+	      cross_eof(STp, FALSE);
 	  STps->eof = ST_FM;
-	}
       }
 
 #if DEBUG
diff -urN linux-2.2.15-pre6/drivers/sound/maestro.c linux/drivers/sound/maestro.c
--- linux-2.2.15-pre6/drivers/sound/maestro.c	Tue Jan  4 10:12:22 2000
+++ linux/drivers/sound/maestro.c	Mon Dec  3 21:59:04 2001
@@ -105,8 +105,24 @@
  *	being used now is quite dirty and assumes we're on a uni-processor
  *	machine.  Much of it will need to be cleaned up for SMP ACPI or 
  *	similar.
+ *
+ *	We also pay attention to PCI power management now.  The driver
+ *	will power down units of the chip that it knows aren't needed.
+ *	The WaveProcessor and company are only powered on when people
+ *	have /dev/dsp*s open.  On removal the driver will
+ *	power down the maestro entirely.  There could still be
+ *	trouble with BIOSen that magically change power states 
+ *	themselves, but we'll see.  
  *	
  * History
+ *  v0.14 - Jan 28 2000 - Zach Brown <zab@redhat.com>
+ *	add PCI power management through ACPI regs.
+ *	we now shut down on machine reboot/halt
+ *	leave scary PCI config items alone (isa stuff, mostly)
+ *	enable 1921s, it seems only mine was broke.
+ *	fix swapped left/right pcm dac.  har har.
+ *	up bob freq, increase buffers, fix pointers at underflow
+ *	silly compilation problems
  *  v0.13 - Nov 18 1999 - Zach Brown <zab@redhat.com>
  *	fix nec Versas?  man would that be cool.
  *  v0.12 - Nov 12 1999 - Zach Brown <zab@redhat.com>
@@ -162,7 +178,22 @@
  *	bob freq code, region sanity, jitter sync fix; all from Eric 
  *
  * TODO
- *	some people get indir reg timeouts?
+ * 	add ref to http://www.booyaka.com/~g00z/alcam/alcam_audio.html
+ *	ac97 power management?
+ *	request_region in _config??
+ *	v0.10 recovers from underrun more quickly than v0.1[34]?
+ *	use new resources and enable_Device in 2.3
+ *	current->state = task_int in for(;;)
+ *	mention 1948 as maestro agogo
+ *	check smp
+ * 	look at spdif, game port
+ *	static linking in 2.3?
+ *	some folks get unexplained constant whine on modprobe, 
+ *		apparently irrespective of mixer settings..
+ *	power apm events (and power down when inactive)
+ *		this should stop indir timeouts on boot
+ *		and randomly falling off to static after while
+ *	make sure real 5.0 works, flash 4 something also
  *	fix bob frequency
  *	endianness
  *	do smart things with ac97 2.0 bits.
@@ -177,11 +208,11 @@
 /*****************************************************************************/
 
 #include <linux/version.h>
-#include <linux/module.h>
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 
  #ifdef MODULE
+  #include <linux/module.h>
   #ifdef MODVERSIONS
    #include <linux/modversions.h>
   #endif
@@ -192,12 +223,16 @@
  #define SILLY_INIT_SEM(SEM) SEM=MUTEX;
  #define init_waitqueue_head init_waitqueue
  #define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC)
+ #define SILLY_OFFSET(VMA) ((VMA)->vm_offset)
+
 
 #else
 
  #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->resource[0].start)
  #define SILLY_INIT_SEM(SEM) init_MUTEX(&SEM)
  #define SILLY_MAKE_INIT(FUNC) __init FUNC
+ #define SILLY_OFFSET(VMA) ((VMA)->vm_pgoff)
+
 
 #endif
 
@@ -214,6 +249,7 @@
 #include <asm/dma.h>
 #include <linux/init.h>
 #include <linux/poll.h>
+#include <linux/reboot.h>
 #include <asm/uaccess.h>
 #include <asm/hardirq.h>
 #include <asm/spinlock.h>
@@ -237,14 +273,18 @@
 
 #ifdef M_DEBUG
 static int debug=0;
-static int dsps_order=0;
 #define M_printk(args...) {if (debug) printk(args);}
 #else
 #define M_printk(x)
 #endif
 
+/* we try to setup 2^(dsps_order) /dev/dsp devices */
+static int dsps_order=0;
+/* wether or not we mess around with power management */
+static int use_pm=2; /* set to 1 for force */
+
 /* --------------------------------------------------------------------- */
-#define DRIVER_VERSION "0.13"
+#define DRIVER_VERSION "0.14"
 
 #ifndef PCI_VENDOR_ESS
 #define PCI_VENDOR_ESS			0x125D
@@ -288,6 +328,46 @@
 #define NR_APUS		64
 #define NR_APU_REGS	16
 
+/* acpi states */
+enum {
+	ACPI_D0=0,
+	ACPI_D1,
+	ACPI_D2,
+	ACPI_D3
+};
+
+/* bits in the acpi masks */
+#define ACPI_12MHZ	( 1 << 15)
+#define ACPI_24MHZ	( 1 << 14)
+#define ACPI_978	( 1 << 13)
+#define ACPI_SPDIF	( 1 << 12)
+#define ACPI_GLUE	( 1 << 11)
+#define ACPI__10	( 1 << 10) /* reserved */
+#define ACPI_PCIINT	( 1 << 9)
+#define ACPI_HV		( 1 << 8) /* hardware volume */
+#define ACPI_GPIO	( 1 << 7)
+#define ACPI_ASSP	( 1 << 6)
+#define ACPI_SB		( 1 << 5) /* sb emul */
+#define ACPI_FM		( 1 << 4) /* fm emul */
+#define ACPI_RB		( 1 << 3) /* ringbus / aclink */
+#define ACPI_MIDI	( 1 << 2) 
+#define ACPI_GP		( 1 << 1) /* game port */
+#define ACPI_WP		( 1 << 0) /* wave processor */
+
+#define ACPI_ALL	(0xffff)
+#define ACPI_SLEEP	(~(ACPI_SPDIF|ACPI_ASSP|ACPI_SB|ACPI_FM| \
+			ACPI_MIDI|ACPI_GP|ACPI_WP))
+#define ACPI_NONE	(ACPI__10)
+
+/* these masks indicate which units we care about at
+	which states */
+u16 acpi_state_mask[] = {
+	[ACPI_D0] = ACPI_ALL,
+	[ACPI_D1] = ACPI_SLEEP,
+	[ACPI_D2] = ACPI_SLEEP,
+	[ACPI_D3] = ACPI_NONE
+};
+
 static const unsigned sample_size[] = { 1, 2, 2, 4 };
 static const unsigned sample_shift[] = { 0, 1, 1, 2 };
 
@@ -309,6 +389,10 @@
 	[TYPE_MAESTRO2E] = (50000000L / 1024L)
 };
 
+static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf);
+
+struct notifier_block maestro_nb = {maestro_notifier, NULL, 0};
+
 /* --------------------------------------------------------------------- */
 
 struct ess_state {
@@ -389,6 +473,8 @@
 		unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
 	} mix;
 	
+	int power_regs;
+		
 	struct ess_state channels[MAX_DSPS];
 	u16 maestro_map[NR_IDRS];	/* Register map */
 #ifdef CONFIG_APM
@@ -405,7 +491,7 @@
 	int dmaorder;
 
 	/* hardware resources */
-	struct pci_dev pcidev; /* uck.. */
+	struct pci_dev *pcidev;
 	u32 iobase;
 	u32 irq;
 
@@ -777,6 +863,10 @@
 		maestro_ac97_set(iobase,0x2c,0x0000);
 		maestro_ac97_set(iobase,0x2c,0xffff);
 		break;
+#if 0	/* i thought the problems I was seeing were with
+	the 1921, but apparently they were with the pci board
+	it was on, so this code is commented out.
+	 lets see if this holds true. */
 	case 0x83847609:	/* ESS 1921 */
 		/* writing to 0xe (mic) or 0x1a (recmask) seems
 			to hang this codec */
@@ -792,6 +882,7 @@
 		udelay(20);
 #endif
 		break;
+#endif
 	default: break;
 	}
 
@@ -1314,11 +1405,12 @@
 			
 /* XXX think about endianess when writing these registers */
 		M_printk("maestro: ess_play_setup: APU[%d] pa = 0x%x\n", ess->apu[channel], pa);
-		/* Load the buffer into the wave engine */
+		/* start of sample */
 		apu_set_register(ess, channel, 4, ((pa>>16)&0xFF)<<8);
 		apu_set_register(ess, channel, 5, pa&0xFFFF);
+		/* sample end */
 		apu_set_register(ess, channel, 6, (pa+size)&0xFFFF);
-		/* setting loop == sample len */
+		/* setting loop len == sample len */
 		apu_set_register(ess, channel, 7, size);
 		
 		/* clear effects/env.. */
@@ -1338,7 +1430,7 @@
 
 		if(mode&ESS_FMT_STEREO) {
 			/* set panning: left or right */
-			apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0x10 : 0));
+			apu_set_register(ess, channel, 10, 0x8F00 | (channel ? 0 : 0x10));
 			ess->apu_mode[channel] += 0x10;
 		} else
 			apu_set_register(ess, channel, 10, 0x8F08);
@@ -1549,7 +1641,7 @@
 	int divide;
 	
 	/* XXX make freq selector much smarter, see calc_bob_rate */
-	int freq = 150;		/* requested frequency - calculate what we want here. */
+	int freq = 200; 
 	
 	/* compute ideal interrupt frequency for buffer size & play rate */
 	/* first, find best prescaler value to match freq */
@@ -1657,6 +1749,7 @@
 
 	db->hwptr = db->swptr = db->total_bytes = db->count = db->error = db->endcleared = 0;
 
+	/* this algorithm is a little nuts.. where did /1000 come from? */
 	bytepersec = rate << sample_shift[fmt];
 	bufs = PAGE_SIZE << db->buforder;
 	if (db->ossfragshift) {
@@ -1685,13 +1778,11 @@
 	memset(db->rawbuf, (fmt & ESS_FMT_16BIT) ? 0 : 0x80, db->dmasize);
 
 	spin_lock_irqsave(&s->lock, flags);
-	if (rec) {
-		ess_rec_setup(s, fmt, s->rateadc, 
-			db->rawbuf, db->numfrag << db->fragshift);
-	} else {
-		ess_play_setup(s, fmt, s->ratedac, 
-			db->rawbuf, db->numfrag << db->fragshift);
-	}
+	if (rec) 
+		ess_rec_setup(s, fmt, s->rateadc, db->rawbuf, db->dmasize);
+	else 
+		ess_play_setup(s, fmt, s->ratedac, db->rawbuf, db->dmasize);
+
 	spin_unlock_irqrestore(&s->lock, flags);
 	db->ready = 1;
 
@@ -1761,7 +1852,7 @@
 		hwptr = get_dmaa(s) % s->dma_dac.dmasize; 
 		/* the apu only reports the length it has seen, not the
 			length of the memory that has been used (the WP
-			knows that */
+			knows that) */
 		if ( ((s->fmt >> ESS_DAC_SHIFT) & ESS_FMT_MASK) == (ESS_FMT_STEREO|ESS_FMT_16BIT))
 			hwptr<<=1;
 
@@ -1778,14 +1869,15 @@
 			s->dma_dac.count -= diff;
 /*			M_printk("maestro: ess_update_ptr: diff: %d, count: %d\n", diff, s->dma_dac.count); */
 			if (s->dma_dac.count <= 0) {
+				M_printk("underflow! diff: %d count: %d hw: %d sw: %d\n", diff, s->dma_dac.count, 
+					hwptr, s->dma_dac.swptr);
 				/* FILL ME 
 				wrindir(s, SV_CIENABLE, s->enable); */
 				/* XXX how on earth can calling this with the lock held work.. */
 				stop_dac(s);
 				/* brute force everyone back in sync, sigh */
 				s->dma_dac.count = 0; 
-				s->dma_dac.swptr = 0; 
-				s->dma_dac.hwptr = 0; 
+				s->dma_dac.swptr = hwptr; 
 				s->dma_dac.error++;
 			} else if (s->dma_dac.count <= (signed)s->dma_dac.fragsize && !s->dma_dac.endcleared) {
 				clear_advance(s);
@@ -1793,6 +1885,8 @@
 			}
 			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize) {
 				wake_up(&s->dma_dac.wait);
+/*				printk("waking up DAC count: %d sw: %d hw: %d\n",s->dma_dac.count, s->dma_dac.swptr, 
+					hwptr);*/
 			}
 		}
 	}
@@ -2302,6 +2396,7 @@
 			if (!ret) ret = -EFAULT;
 			goto return_free;
 		}
+/*		printk("wrote %d bytes at sw: %d cnt: %d while hw: %d\n",cnt, swptr, s->dma_dac.count, s->dma_dac.hwptr);*/
 
 		swptr = (swptr + cnt) % s->dma_dac.dmasize;
 
@@ -2372,7 +2467,7 @@
 	} else  
 #endif
 		return -EINVAL;
-	if (vma->vm_offset != 0)
+	if (SILLY_OFFSET(vma) != 0)
 		return -EINVAL;
 	size = vma->vm_end - vma->vm_start;
 	if (size > (PAGE_SIZE << db->buforder))
@@ -2638,6 +2733,7 @@
 
         case SNDCTL_DSP_SETFRAGMENT:
                 get_user_ret(val, (int *)arg, -EFAULT);
+		M_printk("maestro: SETFRAGMENT: %0x\n",val);
 		if (file->f_mode & FMODE_READ) {
 			s->dma_adc.ossfragshift = val & 0xffff;
 			s->dma_adc.ossmaxfrags = (val >> 16) & 0xffff;
@@ -2703,6 +2799,34 @@
 	wave_set_register(s, 0x01FF , packed_phys);
 }
 
+/* this guy makes sure we're in the right power
+	state for what we want to be doing */
+void maestro_power(struct ess_card *card, int tostate)
+{
+	u16 active_mask = acpi_state_mask[tostate];
+	u8 state;
+
+	if(!use_pm) return;
+
+	pci_read_config_byte(card->pcidev, card->power_regs+0x4, &state);
+	state&=3;
+
+	/* make sure we're in the right state */
+	if(state != tostate) {
+		M_printk(KERN_WARNING "maestro: dev %02x:%02x.%x switching from D%d to D%d\n",
+			card->pcidev->bus->number, 
+			PCI_SLOT(card->pcidev->devfn),
+			PCI_FUNC(card->pcidev->devfn),
+			state,tostate);
+		pci_write_config_byte(card->pcidev, card->power_regs+0x4, tostate);
+	}
+
+	/* and make sure the units we care about are on 
+		XXX we might want to do this before state flipping? */
+	pci_write_config_word(card->pcidev, 0x54, ~ active_mask);
+	pci_write_config_word(card->pcidev, 0x56, ~ active_mask);
+}
+
 /* we allocate a large power of two for all our memory.
 	this is cut up into (not to scale :):
 	|silly fifo word	| 512byte mixbuf per adc	| dac/adc * channels |
@@ -2715,7 +2839,7 @@
 	unsigned long mapend,map;
 
 	/* alloc as big a chunk as we can */
-	for (order = (dsps_order + (15-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--)
+	for (order = (dsps_order + (16-PAGE_SHIFT) + 1); order >= (dsps_order + 2 + 1); order--)
 		if((rawbuf = (void *)__get_free_pages(GFP_KERNEL|GFP_DMA, order)))
 			break;
 
@@ -2734,12 +2858,6 @@
 	s->card->dmapages = rawbuf;
 	s->card->dmaorder = order;
 
-	/* play bufs are in the same first region as record bufs */
-	set_base_registers(s,rawbuf);
-
-	M_printk("maestro: writing %lx (%lx) to the wp\n",virt_to_bus(rawbuf),
-		((virt_to_bus(rawbuf))&0xFFE00000)>>12);
-
 	for(i=0;i<NR_DSPS;i++) {
 		struct ess_state *ess = &s->card->channels[i];
 
@@ -2758,7 +2876,7 @@
 			happily scribble away.. */ 
 		ess->mixbuf = rawbuf + (512 * (i+1));
 
-		M_printk("maestro: setup apu %d: %p %p %p\n",i,ess->dma_dac.rawbuf,
+		M_printk("maestro: setup apu %d: dac: %p adc: %p mix: %p\n",i,ess->dma_dac.rawbuf,
 			ess->dma_adc.rawbuf, ess->mixbuf);
 
 	}
@@ -2844,6 +2962,20 @@
 		return -ENOMEM;
 	}
 
+	/* we're covered by the open_sem */
+	if( ! s->card->dsps_open )  {
+		maestro_power(s->card,ACPI_D0);
+		start_bob(s);
+	}
+	s->card->dsps_open++;
+	M_printk("maestro: open, %d bobs now\n",s->card->dsps_open);
+
+	/* ok, lets write WC base regs now that we've 
+		powered up the chip */
+	M_printk("maestro: writing 0x%lx (bus 0x%lx) to the wp\n",virt_to_bus(s->card->dmapages),
+		((virt_to_bus(s->card->dmapages))&0xFFE00000)>>12);
+	set_base_registers(s,s->card->dmapages);
+
 	if (file->f_mode & FMODE_READ) {
 /*
 		fmtm &= ~((ESS_FMT_STEREO | ESS_FMT_16BIT) << ESS_ADC_SHIFT);
@@ -2867,13 +2999,6 @@
 	set_fmt(s, fmtm, fmts);
 	s->open_mode |= file->f_mode & (FMODE_READ | FMODE_WRITE);
 
-	/* we're covered by the open_sem */
-	if( ! s->card->dsps_open )  {
-		start_bob(s);
-	}
-	s->card->dsps_open++;
-	M_printk("maestro: open, %d bobs now\n",s->card->dsps_open);
-
 	up(&s->open_sem);
 	MOD_INC_USE_COUNT;
 	return 0;
@@ -2899,8 +3024,10 @@
 	/* we're covered by the open_sem */
 	M_printk("maestro: %d dsps now alive\n",s->card->dsps_open-1);
 	if( --s->card->dsps_open <= 0) {
+		s->card->dsps_open = 0;
 		stop_bob(s);
 		free_buffers(s);
+		maestro_power(s->card,ACPI_D2);
 	}
 	up(&s->open_sem);
 	wake_up(&s->open_wait);
@@ -2908,64 +3035,31 @@
 	return 0;
 }
 
-static struct file_operations ess_audio_fops = {
-	&ess_llseek,
-	&ess_read,
-	&ess_write,
-	NULL,  /* readdir */
-	&ess_poll,
-	&ess_ioctl,
-	&ess_mmap,
-	&ess_open,
-	NULL,	/* flush */
-	&ess_release,
-	NULL,  /* fsync */
-	NULL,  /* fasync */
-	NULL,  /* check_media_change */
-	NULL,  /* revalidate */
-	NULL,  /* lock */
-};
-
 static int
 maestro_config(struct ess_card *card) 
 {
-	struct pci_dev *pcidev = &card->pcidev;
+	struct pci_dev *pcidev = card->pcidev;
 	struct ess_state *ess = &card->channels[0];
 	int apu,iobase  = card->iobase;
 	u16 w;
 	u32 n;
 
-	/*
-	 *	Disable ACPI
-	 */
-	 
-	pci_write_config_dword(pcidev, 0x54, 0x00000000);
-	pci_write_config_dword(pcidev, 0x56, 0x00000000);
+	/* We used to muck around with pci config space that
+	we had no business messing with.  We don't know enough
+	about the machine to know which DMA mode is appropriate, 
+	etc.  We were guessing wrong on some machines and making
+	them unhappy.  We now trust in the BIOS to do things right,
+	which almost certainly means a new host of problems will
+	arise with broken BIOS implementations.  screw 'em. 
+	We're already intolerant of machines that don't assign
+	IRQs. */
 	
-	/*
-	 *	Use TDMA for now. TDMA works on all boards, so while its
-	 *	not the most efficient its the simplest.
-	 */ 
+	/* do config work at full power */
+	maestro_power(card,ACPI_D0);
 	 
 	pci_read_config_word(pcidev, 0x50, &w);
 
-	/* Clear DMA bits */
-	w&=~(1<<10|1<<9|1<<8);
-
-	/* TDMA on */
-	w|= (1<<8);
-
-	/*
-	 *	Some of these are undocumented bits
-	 */
-	 
-	w&=~(1<<13)|(1<<14);		/* PIC Snoop mode bits */
-	w&=~(1<<11);			/* Safeguard off */
-	w|= (1<<7);			/* Posted write */
-	w|= (1<<6);			/* ISA timing on */
-	/* XXX huh?  claims to be reserved.. */
-	w&=~(1<<5);			/* Don't swap left/right */
-	w&=~(1<<1);			/* Subtractive decode off */
+	w&=~(1<<5);			/* Don't swap left/right (undoc)*/
 	
 	pci_write_config_word(pcidev, 0x50, w);
 	
@@ -2978,19 +3072,9 @@
 	w&=~(1<<6);		/* Debounce off */
 	w&=~(1<<5);		/* GPIO 4:5 */
 	w|= (1<<4);             /* Disconnect from the CHI.  Enabling this made a dell 7500 work. */
-	w&=~(1<<3);		/* IDMA off (undocumented) */
 	w&=~(1<<2);		/* MIDI fix off (undoc) */
 	w&=~(1<<1);		/* reserved, always write 0 */
-	w&=~(1<<0);		/* IRQ to ISA off (undoc) */
 	pci_write_config_word(pcidev, 0x52, w);
-
-	/*
-	 *	DDMA off
-	 */
-
-	pci_read_config_word(pcidev, 0x60, &w);
-	w&=~(1<<0);
-	pci_write_config_word(pcidev, 0x60, w);
 	
 	/*
 	 *	Legacy mode
@@ -3003,8 +3087,6 @@
 	 
 	pci_write_config_word(pcidev, 0x40, w);
 
-	/* stake our claim on the iospace */
-	request_region(iobase, 256, card_names[card->card_type]);
 	
 	sound_reset(iobase);
 
@@ -3172,6 +3254,57 @@
 	
 }
 
+/* this guy tries to find the pci power management
+ * register bank.  this should really be in core
+ * code somewhere.  1 on success. */
+int
+parse_power(struct ess_card *card, struct pci_dev *pcidev)
+{
+	u32 n;
+	u16 w;
+	u8 next;
+	int max = 64;  /* an a 8bit guy pointing to 32bit guys
+				can only express so much. */
+
+	card->power_regs = 0;
+
+	/* check to see if we have a capabilities list in
+		the config register */
+	pci_read_config_word(pcidev, PCI_STATUS, &w);
+	if(! w & PCI_STATUS_CAP_LIST) return 0;
+
+	/* walk the list, starting at the head. */
+	pci_read_config_byte(pcidev,PCI_CAPABILITY_LIST,&next);
+
+	while(next && max--) {
+		pci_read_config_dword(pcidev, next & ~3, &n);
+		if((n & 0xff) == PCI_CAP_ID_PM) {
+			card->power_regs = next;
+			break;
+		}
+		next = ((n>>8) & 0xff);
+	}
+
+	return card->power_regs ? 1 : 0;
+}
+
+static struct file_operations ess_audio_fops = {
+	&ess_llseek,
+	&ess_read,
+	&ess_write,
+	NULL,  /* readdir */
+	&ess_poll,
+	&ess_ioctl,
+	&ess_mmap,
+	&ess_open,
+	NULL,	/* flush */
+	&ess_release,
+	NULL,  /* fsync */
+	NULL,  /* fasync */
+	NULL,  /* check_media_change */
+	NULL,  /* revalidate */
+	NULL,  /* lock */
+};
 
 static int 
 maestro_install(struct pci_dev *pcidev, int card_type)
@@ -3194,6 +3327,8 @@
 		printk(KERN_WARNING "maestro: can't allocate 256 bytes I/O at 0x%4.4x\n", iobase);
 		return 0;
 	}
+	/* stake our claim on the iospace */
+	request_region(iobase, 256, card_names[card_type]);
 
 	/* this was tripping up some machines */
 	if(pcidev->irq == 0) 
@@ -3212,13 +3347,16 @@
 	}
 	
 	memset(card, 0, sizeof(*card));
-	memcpy(&card->pcidev,pcidev,sizeof(card->pcidev));
+	card->pcidev = pcidev;
 
 #ifdef CONFIG_APM
 	if (apm_register_callback(maestro_apm_callback)) {
 		printk(KERN_WARNING "maestro: apm suspend might not work.\n");
 	}
 #endif
+	if (register_reboot_notifier(&maestro_nb)) {
+		printk(KERN_WARNING "maestro: reboot notifier registration failed; may not reboot properly.\n");
+	}
 
 	card->iobase = iobase;
 	card->card_type = card_type;
@@ -3277,6 +3415,25 @@
 	pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &n);
 	printk(KERN_INFO "maestro:  subvendor id: 0x%08x\n",n); 
 
+	/* turn off power management if it isn't explicitly
+		asked for by the user, we aren't on a 2E, or
+		we aren't on our very small whitelist :) */
+#define SUBSYSTEM_VENDOR(x) (x&0xffff)
+	if(	(use_pm != 1) && 
+		((card_type != TYPE_MAESTRO2E)	|| (SUBSYSTEM_VENDOR(n) != 0x1028)))
+			use_pm = 0;
+
+	if(!use_pm) 
+		printk(KERN_INFO "maestro: not attempting power management.\n");
+	else {
+		if(!parse_power(card,pcidev)) 
+			printk(KERN_INFO "maestro: no PCI power managment interface found.\n");
+		else {
+			pci_read_config_dword(pcidev, card->power_regs, &n);
+			printk(KERN_INFO "maestro: PCI power managment capability: 0x%x\n",n>>16);
+		}	
+	}
+
 	maestro_config(card);
 
 	if(maestro_ac97_get(iobase, 0x00)==0x0080) {
@@ -3307,6 +3464,8 @@
 		kfree(card);
 		return 0;
 	}
+	/* now go to sleep 'till something interesting happens */
+	maestro_power(card,ACPI_D2);
 
 	printk(KERN_INFO "maestro: %d channels configured.\n", num);
 	return 1; 
@@ -3373,44 +3532,66 @@
 	return 0;
 }
 
-/* --------------------------------------------------------------------- */
-
-#ifdef MODULE
-MODULE_AUTHOR("Zach Brown <zab@redhat.com>, Alan Cox <alan@redhat.com>");
-MODULE_DESCRIPTION("ESS Maestro Driver");
-#ifdef M_DEBUG
-MODULE_PARM(debug,"i");
-#endif
-MODULE_PARM(dsps_order,"i");
-
-void cleanup_module(void)
+void nuke_maestros(void)
 {
-	struct ess_card *s;
+	struct ess_card *card;
 
+	/* we do these unconditionally, which is probably wrong */
 #ifdef CONFIG_APM
 	apm_unregister_callback(maestro_apm_callback);
 #endif
-	while ((s = devs)) {
+	unregister_reboot_notifier(&maestro_nb);
+
+	while ((card = devs)) {
 		int i;
 		devs = devs->next;
 	
 		/* XXX maybe should force stop bob, but should be all 
 			stopped by _release by now */
-		free_irq(s->irq, s);
-		unregister_sound_mixer(s->dev_mixer);
+		free_irq(card->irq, card);
+		unregister_sound_mixer(card->dev_mixer);
 		for(i=0;i<NR_DSPS;i++)
 		{
-			struct ess_state *ess = &s->channels[i];
+			struct ess_state *ess = &card->channels[i];
 			if(ess->dev_audio != -1)
 				unregister_sound_dsp(ess->dev_audio);
 		}
-		release_region(s->iobase, 256);
-		kfree(s);
+		/* Goodbye, Mr. Bond. */
+		maestro_power(card,ACPI_D3);
+		release_region(card->iobase, 256);
+		kfree(card);
 	}
+	devs = NULL;
+}
+
+static int maestro_notifier(struct notifier_block *nb, unsigned long event, void *buf)
+{
+	/* this notifier is called when the kernel is really shut down. */
+	M_printk("maestro: shutting down\n");
+	nuke_maestros();
+	return NOTIFY_OK;
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+MODULE_AUTHOR("Zach Brown <zab@redhat.com>, Alan Cox <alan@redhat.com>");
+MODULE_DESCRIPTION("ESS Maestro Driver");
+#ifdef M_DEBUG
+MODULE_PARM(debug,"i");
+#endif
+MODULE_PARM(dsps_order,"i");
+MODULE_PARM(use_pm,"i");
+
+void cleanup_module(void) {
 	M_printk("maestro: unloading\n");
+	nuke_maestros();
 }
 
 #endif /* MODULE */
+
+/* --------------------------------------------------------------------- */
+
 #ifdef CONFIG_APM
 
 void
@@ -3442,6 +3623,10 @@
 
 		M_printk("maestro: apm in dev %p\n",card);
 
+		/* we have to read from the apu regs, need
+			to power it up */
+		maestro_power(card,ACPI_D0);
+
 		for(i=0;i<NR_DSPS;i++) {
 			struct ess_state *s = &card->channels[i];
 
@@ -3464,8 +3649,9 @@
 
 	restore_flags(flags);
 
-	/* we'll let the bios do the rest of the power down.. */
-
+	/* we trust in the bios to power down on suspend.
+	XXX I'm also not sure that in_suspend will protect
+	against all reg accesses from here on out. */
 	return 0;
 }
 static int 
@@ -3474,7 +3660,7 @@
 	struct ess_card *card;
 	unsigned long flags;
 
-	save_flags(flags);
+	save_flags(flags); /* paranoia */
 	cli();
 	in_suspend=0;
 	M_printk("maestro: resuming\n");
@@ -3485,6 +3671,7 @@
 
 		M_printk("maestro: apm in dev %p\n",card);
 
+		/* restore all our config */
 		maestro_config(card);
 		/* need to restore the base pointers.. */ 
 		if(card->dmapages) 
@@ -3515,6 +3702,16 @@
 
 		M_printk("maestro: apm in dev %p\n",card);
 
+		if( card->dsps_open <= 0) {
+			/* this card's idle */
+			maestro_power(card,ACPI_D2);
+			continue;
+		}
+
+		/* ok, we're actually playing things on
+			this card */
+		maestro_power(card,ACPI_D0);
+		start_bob(&card->channels[0]);
 		for(i=0;i<NR_DSPS;i++) {
 			struct ess_state *s = &card->channels[i];
 
@@ -3523,12 +3720,13 @@
 			start_dac(s);	
 			start_adc(s);	
 		}
-		if( card->dsps_open > 0)
-			start_bob(&card->channels[0]);
 	}
 
 	restore_flags(flags);
 
+	/* all right, we think things are ready, 
+		wake up people who were using the device
+		when we suspended */
 	wake_up(&suspend_queue);
 
 	return 0;
@@ -3536,8 +3734,9 @@
 
 int 
 maestro_apm_callback(apm_event_t ae) {
+	struct ess_card *card;
 
-	M_printk("maestro: apm event received: 0x%x\n",ae);
+	M_printk("maestro: APM event received: 0x%x\n",ae);
 
 	switch(ae) {
 	case APM_SYS_SUSPEND: 
@@ -3548,6 +3747,15 @@
 	case APM_CRITICAL_RESUME: 
 	case APM_STANDBY_RESUME: 
 		maestro_resume();break;
+	case APM_POWER_STATUS_CHANGE:
+		for(card = devs ; card ; card = card->next) {
+			maestro_power(card, (card->dsps_open>0) ? ACPI_D0 : ACPI_D2);
+			/* XXX we're probably screwed here.  If the bios
+			drops the regs out from under us we'll have to actively
+			rebuild them.  This would look alot like the things
+			we do at _resume. */
+		}
+		break;
 	default: break;
 	}
 
diff -urN linux-2.2.15-pre6/fs/select.c linux/fs/select.c
--- linux-2.2.15-pre6/fs/select.c	Wed Aug 25 17:29:49 1999
+++ linux/fs/select.c	Mon Dec  3 21:59:04 2001
@@ -39,6 +39,39 @@
  * Linus noticed.  -- jrs
  */
 
+static poll_table* alloc_wait(int nfds)
+{
+	poll_table* out;
+	poll_table* walk;
+
+	out = (poll_table *) __get_free_page(GFP_KERNEL);
+	if(out==NULL)
+		return NULL;
+	out->nr = 0;
+	out->entry = (struct poll_table_entry *)(out + 1);
+	out->next = NULL;
+	nfds -=__MAX_POLL_TABLE_ENTRIES;
+	walk = out;
+	while(nfds > 0) {
+		poll_table *tmp = (poll_table *) __get_free_page(GFP_KERNEL);
+		if (!tmp) {
+			while(out != NULL) {
+				tmp = out->next;
+				free_page((unsigned long)out);
+				out = tmp;
+			}
+			return NULL;
+		}
+		tmp->nr = 0;
+		tmp->entry = (struct poll_table_entry *)(tmp + 1);
+		tmp->next = NULL;
+		walk->next = tmp;
+		walk = tmp;
+		nfds -=__MAX_POLL_TABLE_ENTRIES;
+	}
+	return out;
+}
+
 static void free_wait(poll_table * p)
 {
 	struct poll_table_entry * entry;
@@ -63,7 +96,6 @@
 	for (;;) {
 		if (p->nr < __MAX_POLL_TABLE_ENTRIES) {
 			struct poll_table_entry * entry;
-ok_table:
 		 	entry = p->entry + p->nr;
 		 	entry->filp = filp;
 		 	filp->f_count++;
@@ -74,17 +106,6 @@
 			p->nr++;
 			return;
 		}
-		if (p->next == NULL) {
-			poll_table *tmp = (poll_table *) __get_free_page(GFP_KERNEL);
-			if (!tmp)
-				return;
-			tmp->nr = 0;
-			tmp->entry = (struct poll_table_entry *)(tmp + 1);
-			tmp->next = NULL;
-			p->next = tmp;
-			p = tmp;
-			goto ok_table;
-		}
 		p = p->next;
 	}
 }
@@ -154,23 +175,21 @@
 	long __timeout = *timeout;
 
 	wait = wait_table = NULL;
-	if (__timeout) {
-		wait_table = (poll_table *) __get_free_page(GFP_KERNEL);
-		if (!wait_table)
-			return -ENOMEM;
-
-		wait_table->nr = 0;
-		wait_table->entry = (struct poll_table_entry *)(wait_table + 1);
-		wait_table->next = NULL;
-		wait = wait_table;
-	}
-
 	lock_kernel();
 
 	retval = max_select_fd(n, fds);
 	if (retval < 0)
 		goto out;
 	n = retval;
+	if (__timeout) {
+		retval = -ENOMEM;
+		wait_table = alloc_wait(n);
+		if (!wait_table)
+			goto out;
+
+		wait = wait_table;
+	}
+
 	retval = 0;
 	for (;;) {
 		current->state = TASK_INTERRUPTIBLE;
@@ -406,12 +425,10 @@
 
 	err = -ENOMEM;
 	if (timeout) {
-		wait_table = (poll_table *) __get_free_page(GFP_KERNEL);
+		wait_table = alloc_wait(nfds);
 		if (!wait_table)
 			goto out;
-		wait_table->nr = 0;
-		wait_table->entry = (struct poll_table_entry *)(wait_table + 1);
-		wait_table->next = NULL;
+
 		wait = wait_table;
 	}
 
diff -urN linux-2.2.15-pre6/ipc/shm.c linux/ipc/shm.c
--- linux-2.2.15-pre6/ipc/shm.c	Mon Dec  3 21:58:58 2001
+++ linux/ipc/shm.c	Mon Dec  3 21:59:04 2001
@@ -634,7 +634,7 @@
 	/* This can occur on a remap */
 	
 	if (idx >= shp->shm_npages) {
-		return NULL;
+		return 0;
 	}
 
 	pte = __pte(shp->shm_pages[idx]);
diff -urN linux-2.2.15-pre6/mm/page_alloc.c linux/mm/page_alloc.c
--- linux-2.2.15-pre6/mm/page_alloc.c	Mon Dec  3 21:58:58 2001
+++ linux/mm/page_alloc.c	Mon Dec  3 21:59:04 2001
@@ -210,18 +210,17 @@
 	 */
 	if (!(current->flags & PF_MEMALLOC)) {
 		int freed;
+#ifdef SLEEP_MEMORY_DEBUGGING
 		if (current->state != TASK_RUNNING && (gfp_mask & __GFP_WAIT)) {
 			printk("gfp called by non-running (%d) task from %p!\n",
 				current->state, __builtin_return_address(0));
 			/* if we're not running, we can't sleep */
 			gfp_mask &= ~__GFP_WAIT;
 		}
+#endif		
 
 		if (nr_free_pages <= freepages.low) {
 			wake_up_interruptible(&kswapd_wait);
-			/* a bit of defensive programming */
-			if (gfp_mask & __GFP_WAIT)
-				schedule();
 		}
 		if (nr_free_pages > freepages.min)
 			goto ok_to_allocate;
diff -urN linux-2.2.15-pre6/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- linux-2.2.15-pre6/net/ax25/af_ax25.c	Tue Jan  4 10:12:26 2000
+++ linux/net/ax25/af_ax25.c	Mon Dec  3 21:59:04 2001
@@ -96,6 +96,7 @@
  *      AX.25 038       Matthias(DG2FEF)        Small fixes to the syscall interface to make kernel
  *                                              independent of AX25_MAX_DIGIS used by applications.
  *                      Tomi(OH2BNS)            Fixed ax25_getname().
+ *                      Tomi(OH2BNS)            recvmsg() returns source not dest in msg.
  */
 
 #include <linux/config.h>
@@ -1482,16 +1483,16 @@
 	if (msg->msg_namelen != 0) {
 		struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;
 		ax25_digi digi;
-		ax25_address dest;
+		ax25_address src;
 
-		ax25_addr_parse(skb->mac.raw+1, skb->data-skb->mac.raw-1, NULL, &dest, &digi, NULL, NULL);
+		ax25_addr_parse(skb->mac.raw+1, skb->data-skb->mac.raw-1, &src, NULL, &digi, NULL, NULL);
 
 		sax->sax25_family = AF_AX25;
 		/* We set this correctly, even though we may not let the
 		   application know the digi calls further down (because it
 		   did NOT ask to know them).  This could get political... **/
 		sax->sax25_ndigis = digi.ndigi;
-		sax->sax25_call   = dest;
+		sax->sax25_call   = src;
 
 		if (sax->sax25_ndigis != 0) {
 			int ct;
diff -urN linux-2.2.15-pre6/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- linux-2.2.15-pre6/net/ipv4/tcp.c	Mon Dec  3 21:58:58 2001
+++ linux/net/ipv4/tcp.c	Mon Dec  3 21:59:04 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.140.2.8 2000/01/27 22:33:35 davem Exp $
+ * Version:	$Id: tcp.c,v 1.140.2.9 2000/02/07 20:20:00 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
diff -urN linux-2.2.15-pre6/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- linux-2.2.15-pre6/net/ipv4/tcp_output.c	Mon Dec  3 21:58:58 2001
+++ linux/net/ipv4/tcp_output.c	Mon Dec  3 21:59:04 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_output.c,v 1.108.2.5 2000/01/14 01:22:18 davem Exp $
+ * Version:	$Id: tcp_output.c,v 1.108.2.6 2000/02/07 20:20:11 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
