[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#296677: kernel-source-2.6.10: Please consider include Guido Guenther powerpc patches



Package: kernel-source-2.6.10
Severity: wishlist
Tags: patch


Good day,

Guido Guenther maintains some patches against 2.6 that I found very
usefull : 

software suspend : 

>From debian-ppc : 

| On Wed, Feb 23, 2005 at 11:54:20AM +1100, Benjamin Herrenschmidt wrote:
| > > I also gather that suspend-to-disk is available -
| > > http://article.gmane.org/gmane.linux.debian.ports.powerpc/25379 
| >
| > I don't think suspend to disk is very reliable tho ...
| Works here without problems for several days now, patch is at
|  http://honk.physik.uni-konstanz.de/~agx/linux-ppc/kernel/2.6.11-rc4-agx0.diff
| Cheers,
|  -- Guido


Again From debian-ppc on 04 december 2004 :

| The patch contains some other small goodies such as a selectable HZ
| value (default is 1000, 100 saves some battery) and some alsa and
| cpufreq fixes.
| Please note that this patch still conflicts with suspend to ram, so you
| won't be able to use both.
| Cheers,
|  -- Guido 


patch is at : 
http://honk.physik.uni-konstanz.de/~agx/linux-ppc/kernel/

and attached to this bug report.

Regards.

-- System Information:
Debian Release: 3.1
  APT prefers unstable
  APT policy: (500, 'unstable')
Architecture: powerpc (ppc)
Kernel: Linux 2.6.9-rfb-swsusp
Locale: LANG=fr_FR@euro, LC_CTYPE=fr_FR@euro (charmap=ISO-8859-15)
diff -u -Naur linux-2.6.10.orig/arch/ppc/Kconfig linux-2.6.10/arch/ppc/Kconfig
--- linux-2.6.10.orig/arch/ppc/Kconfig	2004-12-24 22:35:40.000000000 +0100
+++ linux-2.6.10/arch/ppc/Kconfig	2005-01-04 14:21:32.583281000 +0100
@@ -966,6 +966,15 @@
 
 source "drivers/zorro/Kconfig"
 
+source kernel/power/Kconfig
+
+config PPC_HZ
+       int "Clock Tick Rate"
+       default 1000
+       help
+         Select the kernel clock tick rate in interrupts per second.
+         Slower processors should choose 100; everything else 1000.
+
 endmenu
 
 menu "Bus options"
diff -u -Naur linux-2.6.10.orig/arch/ppc/kernel/Makefile linux-2.6.10/arch/ppc/kernel/Makefile
--- linux-2.6.10.orig/arch/ppc/kernel/Makefile	2004-12-24 22:35:28.000000000 +0100
+++ linux-2.6.10/arch/ppc/kernel/Makefile	2005-01-04 14:21:32.583281000 +0100
@@ -16,6 +16,7 @@
 					semaphore.o syscalls.o setup.o \
 					cputable.o ppc_htab.o
 obj-$(CONFIG_6xx)		+= l2cr.o cpu_setup_6xx.o
+obj-$(CONFIG_SOFTWARE_SUSPEND)	+= swsusp.o
 obj-$(CONFIG_POWER4)		+= cpu_setup_power4.o
 obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
 obj-$(CONFIG_NOT_COHERENT_CACHE)	+= dma-mapping.o
diff -u -Naur linux-2.6.10.orig/arch/ppc/kernel/signal.c linux-2.6.10/arch/ppc/kernel/signal.c
--- linux-2.6.10.orig/arch/ppc/kernel/signal.c	2004-12-24 22:35:39.000000000 +0100
+++ linux-2.6.10/arch/ppc/kernel/signal.c	2005-01-04 14:21:32.583281000 +0100
@@ -28,6 +28,7 @@
 #include <linux/elf.h>
 #include <linux/tty.h>
 #include <linux/binfmts.h>
+#include <linux/suspend.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -614,6 +615,14 @@
 	unsigned long frame, newsp;
 	int signr, ret;
 
+	if (current->flags & PF_FREEZE) {
+		refrigerator(PF_FREEZE);
+		signr = 0;
+		ret = regs->gpr[3];
+		if (!signal_pending(current))
+			goto no_signal;
+	}
+
 	if (!oldset)
 		oldset = &current->blocked;
 
@@ -636,6 +645,7 @@
 			regs->gpr[3] = EINTR;
 			/* note that the cr0.SO bit is already set */
 		} else {
+no_signal:
 			regs->nip -= 4;	/* Back up & retry system call */
 			regs->result = 0;
 			regs->trap = 0;
diff -u -Naur linux-2.6.10.orig/arch/ppc/kernel/swsusp.S linux-2.6.10/arch/ppc/kernel/swsusp.S
--- linux-2.6.10.orig/arch/ppc/kernel/swsusp.S	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/arch/ppc/kernel/swsusp.S	2005-01-04 14:21:32.583281000 +0100
@@ -0,0 +1,356 @@
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/cputable.h>
+#include <asm/thread_info.h>
+#include <asm/ppc_asm.h>
+#include <asm/offsets.h>
+
+
+/*
+ * Structure for storing CPU registers on the save area.
+ */
+#define SL_SP		0
+#define SL_PC		4
+#define SL_MSR		8
+#define SL_SDR1		0xc
+#define SL_SPRG0	0x10	/* 4 sprg's */
+#define SL_DBAT0	0x20
+#define SL_IBAT0	0x28
+#define SL_DBAT1	0x30
+#define SL_IBAT1	0x38
+#define SL_DBAT2	0x40
+#define SL_IBAT2	0x48
+#define SL_DBAT3	0x50
+#define SL_IBAT3	0x58
+#define SL_TB		0x60
+#define SL_R2		0x68
+#define SL_CR		0x6c
+#define SL_LR		0x70
+#define SL_R12		0x74	/* r12 to r31 */
+#define SL_SIZE		(SL_R12 + 80)
+
+	.section .data
+	.align	5
+
+_GLOBAL(swsusp_save_area)
+	.space	SL_SIZE
+
+
+	.section .text
+	.align	5
+
+_GLOBAL(swsusp_arch_suspend)
+
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+
+	mflr	r0
+	stw	r0,SL_LR(r11)
+	mfcr	r0
+	stw	r0,SL_CR(r11)
+	stw	r1,SL_SP(r11)
+	stw	r2,SL_R2(r11)
+	stmw	r12,SL_R12(r11)
+
+	/* Save MSR & SDR1 */
+	mfmsr	r4
+	stw	r4,SL_MSR(r11)
+	mfsdr1	r4
+	stw	r4,SL_SDR1(r11)
+
+	/* Get a stable timebase and save it */
+1:	mftbu	r4
+	stw	r4,SL_TB(r11)
+	mftb	r5
+	stw	r5,SL_TB+4(r11)
+	mftbu	r3
+	cmpw	r3,r4
+	bne	1b
+
+	/* Save SPRGs */
+	mfsprg	r4,0
+	stw	r4,SL_SPRG0(r11)
+	mfsprg	r4,1
+	stw	r4,SL_SPRG0+4(r11)
+	mfsprg	r4,2
+	stw	r4,SL_SPRG0+8(r11)
+	mfsprg	r4,3
+	stw	r4,SL_SPRG0+12(r11)
+
+	/* Save BATs */
+	mfdbatu	r4,0
+	stw	r4,SL_DBAT0(r11)
+	mfdbatl	r4,0
+	stw	r4,SL_DBAT0+4(r11)
+	mfdbatu	r4,1
+	stw	r4,SL_DBAT1(r11)
+	mfdbatl	r4,1
+	stw	r4,SL_DBAT1+4(r11)
+	mfdbatu	r4,2
+	stw	r4,SL_DBAT2(r11)
+	mfdbatl	r4,2
+	stw	r4,SL_DBAT2+4(r11)
+	mfdbatu	r4,3
+	stw	r4,SL_DBAT3(r11)
+	mfdbatl	r4,3
+	stw	r4,SL_DBAT3+4(r11)
+	mfibatu	r4,0
+	stw	r4,SL_IBAT0(r11)
+	mfibatl	r4,0
+	stw	r4,SL_IBAT0+4(r11)
+	mfibatu	r4,1
+	stw	r4,SL_IBAT1(r11)
+	mfibatl	r4,1
+	stw	r4,SL_IBAT1+4(r11)
+	mfibatu	r4,2
+	stw	r4,SL_IBAT2(r11)
+	mfibatl	r4,2
+	stw	r4,SL_IBAT2+4(r11)
+	mfibatu	r4,3
+	stw	r4,SL_IBAT3(r11)
+	mfibatl	r4,3
+	stw	r4,SL_IBAT3+4(r11)
+
+#if  0
+	/* Backup various CPU config stuffs */
+	bl	__save_cpu_setup
+#endif
+	/* Call the low level suspend stuff (we should probably have made
+	 * a stackframe...
+	 */
+	bl	swsusp_save
+
+	/* Restore LR from the save area */
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+	lwz	r0,SL_LR(r11)
+	mtlr	r0
+
+	blr
+
+
+/* Resume code */
+_GLOBAL(swsusp_arch_resume)
+
+	/* Stop pending alitvec streams and memory accesses */
+BEGIN_FTR_SECTION
+	DSSALL
+END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
+ 	sync
+
+	/* Disable MSR:DR to make sure we don't take a TLB or
+	 * hash miss during the copy, as our hash table will
+	 * for a while be unuseable. For .text, we assume we are
+	 * covered by a BAT. This works only for non-G5 at this
+	 * point. G5 will need a better approach, possibly using
+	 * a small temporary hash table filled with large mappings,
+	 * disabling the MMU completely isn't a good option for
+	 * performance reasons.
+	 * (Note that 750's may have the same performance issue as
+	 * the G5 in this case, we should investigate using moving
+	 * BATs for these CPUs)
+	 */
+	mfmsr	r0
+	sync
+	rlwinm	r0,r0,0,28,26		/* clear MSR_DR */
+	mtmsr	r0
+	sync
+	isync
+
+	/* Load ptr the list of pages to copy in r3 */
+	lis	r11,(pagedir_nosave - KERNELBASE)@h
+	ori	r11,r11,pagedir_nosave@l
+	lwz	r10,0(r11)
+	tophys(r3,r10)
+
+	/* Load the count of pages to copy in r4 */
+	lis	r11,(nr_copy_pages - KERNELBASE)@h
+	ori	r11,r11,nr_copy_pages@l
+	lwz	r4,0(r11)
+
+
+	/* Copy the pages. This is a very basic implementation, to
+	 * be replaced by something more cache efficient */
+1:
+	li	r0,256
+	mtctr	r0
+	lwz	r11,0(r3)	/* source */
+	tophys(r5,r11)
+	lwz	r10,4(r3)	/* destination */
+	tophys(r6,r10)
+2:
+	lwz	r8,0(r5)
+	lwz	r9,4(r5)
+	lwz	r10,8(r5)
+	lwz	r11,12(r5)
+	addi	r5,r5,16
+	stw	r8,0(r6)
+	stw	r9,4(r6)
+	stw	r10,8(r6)
+	stw	r11,12(r6)
+	addi	r6,r6,16
+	bdnz	2b
+	addi	r3,r3,16
+	subi	r4,r4,1
+	cmpwi	0,r4,0
+	bne	1b
+
+	/* Do a very simple cache flush/inval of the L1 to ensure
+	 * coherency of the icache
+	 */
+	lis	r3,0x0002
+	mtctr	r3
+	li	r3, 0
+1:
+	lwz	r0,0(r3)
+	addi	r3,r3,0x0020
+	bdnz	1b
+	isync
+	sync
+
+	/* Now flush those cache lines */
+	lis	r3,0x0002
+	mtctr	r3
+	li	r3, 0
+1:
+	dcbf	0,r3
+	addi	r3,r3,0x0020
+	bdnz	1b
+	sync
+
+	/* Ok, we are now running with the kernel data of the old
+	 * kernel fully restored. We can get to the save area
+	 * easily now. As for the rest of the code, it assumes the
+	 * loader kernel and the booted one are exactly identical
+	 */
+	lis	r11,swsusp_save_area@h
+	ori	r11,r11,swsusp_save_area@l
+	tophys(r11,r11)
+
+#if 0
+	/* Restore various CPU config stuffs */
+	bl	__restore_cpu_setup
+#endif
+	/* Restore the BATs, and SDR1.  Then we can turn on the MMU.
+	 * This is a bit hairy as we are running out of those BATs,
+	 * but first, our code is probably in the icache, and we are
+	 * writing the same value to the BAT, so that should be fine,
+	 * though a better solution will have to be found long-term
+	 */
+	lwz	r4,SL_SDR1(r11)
+	mtsdr1	r4
+	lwz	r4,SL_SPRG0(r11)
+	mtsprg	0,r4
+	lwz	r4,SL_SPRG0+4(r11)
+	mtsprg	1,r4
+	lwz	r4,SL_SPRG0+8(r11)
+	mtsprg	2,r4
+	lwz	r4,SL_SPRG0+12(r11)
+	mtsprg	3,r4
+
+#if 0
+	lwz	r4,SL_DBAT0(r11)
+	mtdbatu	0,r4
+	lwz	r4,SL_DBAT0+4(r11)
+	mtdbatl	0,r4
+	lwz	r4,SL_DBAT1(r11)
+	mtdbatu	1,r4
+	lwz	r4,SL_DBAT1+4(r11)
+	mtdbatl	1,r4
+	lwz	r4,SL_DBAT2(r11)
+	mtdbatu	2,r4
+	lwz	r4,SL_DBAT2+4(r11)
+	mtdbatl	2,r4
+	lwz	r4,SL_DBAT3(r11)
+	mtdbatu	3,r4
+	lwz	r4,SL_DBAT3+4(r11)
+	mtdbatl	3,r4
+	lwz	r4,SL_IBAT0(r11)
+	mtibatu	0,r4
+	lwz	r4,SL_IBAT0+4(r11)
+	mtibatl	0,r4
+	lwz	r4,SL_IBAT1(r11)
+	mtibatu	1,r4
+	lwz	r4,SL_IBAT1+4(r11)
+	mtibatl	1,r4
+	lwz	r4,SL_IBAT2(r11)
+	mtibatu	2,r4
+	lwz	r4,SL_IBAT2+4(r11)
+	mtibatl	2,r4
+	lwz	r4,SL_IBAT3(r11)
+	mtibatu	3,r4
+	lwz	r4,SL_IBAT3+4(r11)
+	mtibatl	3,r4
+#endif
+
+BEGIN_FTR_SECTION
+	li	r4,0
+	mtspr	SPRN_DBAT4U,r4
+	mtspr	SPRN_DBAT4L,r4
+	mtspr	SPRN_DBAT5U,r4
+	mtspr	SPRN_DBAT5L,r4
+	mtspr	SPRN_DBAT6U,r4
+	mtspr	SPRN_DBAT6L,r4
+	mtspr	SPRN_DBAT7U,r4
+	mtspr	SPRN_DBAT7L,r4
+	mtspr	SPRN_IBAT4U,r4
+	mtspr	SPRN_IBAT4L,r4
+	mtspr	SPRN_IBAT5U,r4
+	mtspr	SPRN_IBAT5L,r4
+	mtspr	SPRN_IBAT6U,r4
+	mtspr	SPRN_IBAT6L,r4
+	mtspr	SPRN_IBAT7U,r4
+	mtspr	SPRN_IBAT7L,r4
+END_FTR_SECTION_IFSET(CPU_FTR_HAS_HIGH_BATS)
+
+	/* Flush all TLBs */
+	lis	r4,0x1000
+1:	addic.	r4,r4,-0x1000
+	tlbie	r4
+	blt	1b
+	sync
+
+	/* restore the MSR and turn on the MMU */
+	lwz	r3,SL_MSR(r11)
+	bl	turn_on_mmu
+	tovirt(r11,r11)
+
+	/* Restore TB */
+	li	r3,0
+	mttbl	r3
+	lwz	r3,SL_TB(r11)
+	lwz	r4,SL_TB+4(r11)
+	mttbu	r3
+	mttbl	r4
+
+	/* Kick decrementer */
+	li	r0,1
+	mtdec	r0
+
+	/* Restore the callee-saved registers and return */
+	lwz	r0,SL_CR(r11)
+	mtcr	r0
+	lwz	r2,SL_R2(r11)
+	lmw	r12,SL_R12(r11)
+	lwz	r1,SL_SP(r11)
+	lwz	r0,SL_LR(r11)
+	mtlr	r0
+
+	// XXX Note: we don't really need to call swsusp_resume
+
+	li	r3,0
+	blr
+
+/* FIXME:This construct is actually not useful since we don't shut
+ * down the instruction MMU, we could just flip back MSR-DR on.
+ */
+turn_on_mmu:
+	mflr	r4
+	mtsrr0	r4
+	mtsrr1	r3
+	sync
+	isync
+	rfi
+
diff -u -Naur linux-2.6.10.orig/arch/ppc/kernel/vmlinux.lds.S linux-2.6.10/arch/ppc/kernel/vmlinux.lds.S
--- linux-2.6.10.orig/arch/ppc/kernel/vmlinux.lds.S	2004-12-24 22:35:50.000000000 +0100
+++ linux-2.6.10/arch/ppc/kernel/vmlinux.lds.S	2005-01-04 14:21:32.593281000 +0100
@@ -74,6 +74,12 @@
     CONSTRUCTORS
   }
 
+  . = ALIGN(4096);
+  __nosave_begin = .;
+  .data_nosave : { *(.data.nosave) }
+  . = ALIGN(4096);
+  __nosave_end = .;
+
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
diff -u -Naur linux-2.6.10.orig/arch/ppc/platforms/pmac_cpufreq.c linux-2.6.10/arch/ppc/platforms/pmac_cpufreq.c
--- linux-2.6.10.orig/arch/ppc/platforms/pmac_cpufreq.c	2004-12-24 22:34:58.000000000 +0100
+++ linux-2.6.10/arch/ppc/platforms/pmac_cpufreq.c	2005-01-04 14:21:32.593281000 +0100
@@ -36,6 +36,7 @@
 #include <asm/system.h>
 #include <asm/open_pic.h>
 
+#define dprintk(msg...) cpufreq_debug_printk(CPUFREQ_DEBUG_DRIVER, "pmac-cpufreq", msg)
 /* WARNING !!! This will cause calibrate_delay() to be called,
  * but this is an __init function ! So you MUST go edit
  * init/main.c to make it non-init before enabling DEBUG_FREQ
@@ -118,14 +119,12 @@
  */
 static int __pmac cpu_750fx_cpu_speed(int low_speed)
 {
-#ifdef DEBUG_FREQ
-	printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
-#endif
+	dprintk("HID1, before: %x\n", mfspr(SPRN_HID1));
 #ifdef CONFIG_6xx
 	low_choose_750fx_pll(low_speed);
 #endif
+	dprintk("HID1, after: %x\n", mfspr(SPRN_HID1));
 #ifdef DEBUG_FREQ
-	printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
 	debug_calc_bogomips();
 #endif
 
@@ -202,9 +201,7 @@
 
 	preempt_disable();
 
-#ifdef DEBUG_FREQ
-	printk(KERN_DEBUG "HID1, before: %x\n", mfspr(SPRN_HID1));
-#endif
+	dprintk("HID1, before: %x\n", mfspr(SPRN_HID1));
 	/* Disable all interrupt sources on openpic */
  	openpic_set_priority(0xf);
 
@@ -262,9 +259,7 @@
 	/* Restore userland MMU context */
 	set_context(current->active_mm->context, current->active_mm->pgd);
 
-#ifdef DEBUG_FREQ
-	printk(KERN_DEBUG "HID1, after: %x\n", mfspr(SPRN_HID1));
-#endif
+	dprintk("HID1, after: %x\n", mfspr(SPRN_HID1));
 
 	/* Restore low level PMU operations */
 	pmu_unlock();
@@ -354,14 +349,40 @@
 	return 0x50 + (*reg);
 }
 
+static struct freq_attr* pmac_cpufreq_attr[] = { 
+        &cpufreq_freq_attr_scaling_available_freqs,
+        NULL,
+};
+
 static struct cpufreq_driver pmac_cpufreq_driver = {
 	.verify 	= pmac_cpufreq_verify,
 	.target 	= pmac_cpufreq_target,
 	.init		= pmac_cpufreq_cpu_init,
 	.name		= "powermac",
 	.owner		= THIS_MODULE,
+	.attr		= pmac_cpufreq_attr,
 };
 
+static unsigned int __pmac pmac_cpufreq_get_pmu(unsigned int cpu)
+{
+	if (cpu)
+		return -ENODEV;
+	/* FIXME: we need to get the frequency properly */
+	return	cur_freq;
+}
+
+
+static unsigned int __pmac pmac_cpufreq_get_gpios(unsigned int cpu)
+{
+	struct device_node *freq_gpio_np = of_find_node_by_name(NULL,
+								"frequency-gpio");
+	int rc;
+
+	frequency_gpio = read_gpio(freq_gpio_np);
+	rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
+	return (rc & 0x01) ? hi_freq : low_freq;
+}
+
 
 static int __pmac pmac_cpufreq_init_MacRISC3(struct device_node *cpunode)
 {
@@ -371,6 +392,7 @@
 								"frequency-gpio");
 	struct device_node *slew_done_gpio_np = of_find_node_by_name(NULL,
 								     "slewing-done");
+	struct cpufreq_driver *driver = &pmac_cpufreq_driver;
 	u32 *value;
 
 	/*
@@ -395,6 +417,7 @@
 		int lenp, rc;
 		u32 *freqs, *ratio;
 
+		dprintk("Using GIO");
 		freqs = (u32 *)get_property(cpunode, "bus-frequencies", &lenp);
 		lenp /= sizeof(u32);
 		if (freqs == NULL || lenp != 2) {
@@ -423,14 +446,15 @@
 		low_freq = (low_freq * (*ratio)) / 2000;
 		hi_freq = (hi_freq * (*ratio)) / 2000;
 
-		/* Now we get the frequencies, we read the GPIO to see what is out current
+		/* Now we get the frequencies, we read the GPIO to see what is our current
 		 * speed
 		 */
 		rc = pmac_call_feature(PMAC_FTR_READ_GPIO, NULL, frequency_gpio, 0);
 		cur_freq = (rc & 0x01) ? hi_freq : low_freq;
 
 		set_speed_proc = gpios_set_cpu_speed;
-		return 1;
+		driver->get = pmac_cpufreq_get_gpios;
+		return 0;
 	}
 
 	/* If we use the PMU, look for the min & max frequencies in the
@@ -450,22 +474,31 @@
 		return 1;
 	hi_freq = (*value) / 1000;
 	set_speed_proc = pmu_set_cpu_speed;
+	dprintk("Using PMU");
+	driver->get = pmac_cpufreq_get_pmu;
 
 	return 0;
 }
 
+static unsigned int __pmac pmac_cpufreq_get_7447A(unsigned int cpu)
+{
+	if (mfspr(HID1) & HID1_DFS)
+		return low_freq;
+	else
+		return hi_freq;
+}
+
 static int __pmac pmac_cpufreq_init_7447A(struct device_node *cpunode)
 {
 	struct device_node *volt_gpio_np;
 	u32 *reg;
+	struct cpufreq_driver *driver = &pmac_cpufreq_driver;
 
 	/* OF only reports the high frequency */
 	hi_freq = cur_freq;
 	low_freq = cur_freq/2;
-	if (mfspr(HID1) & HID1_DFS)
-		cur_freq = low_freq;
-	else
-		cur_freq = hi_freq;
+	driver->get = pmac_cpufreq_get_7447A;
+	cur_freq = driver->get(0);
 
 	volt_gpio_np = of_find_node_by_name(NULL, "cpu-vcore-select");
 	if (!volt_gpio_np){
diff -u -Naur linux-2.6.10.orig/arch/ppc/platforms/pmac_setup.c linux-2.6.10/arch/ppc/platforms/pmac_setup.c
--- linux-2.6.10.orig/arch/ppc/platforms/pmac_setup.c	2004-12-24 22:35:01.000000000 +0100
+++ linux-2.6.10/arch/ppc/platforms/pmac_setup.c	2005-01-04 14:21:32.593281000 +0100
@@ -52,6 +52,7 @@
 #include <linux/seq_file.h>
 #include <linux/root_dev.h>
 #include <linux/bitops.h>
+#include <linux/suspend.h>
 
 #include <asm/reg.h>
 #include <asm/sections.h>
@@ -70,6 +71,8 @@
 #include <asm/pmac_feature.h>
 #include <asm/time.h>
 #include <asm/of_device.h>
+#include <asm/mmu_context.h>
+
 #include "pmac_pic.h"
 #include "mem_pieces.h"
 
@@ -421,10 +424,62 @@
 }
 
 static int initializing = 1;
+/* TODO: Merge the suspend-to-ram with the common code !!!
+ * currently, this is a stub implementation for suspend-to-disk
+ * only
+ */
+
+#ifdef CONFIG_SOFTWARE_SUSPEND
+
+static int pmac_pm_prepare(suspend_state_t state)
+{
+	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+	return 0;
+}
+
+static int pmac_pm_enter(suspend_state_t state)
+{
+	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+	/* Giveup the lazy FPU & vec so we don't have to back them
+	 * up from the low level code
+	 */
+	enable_kernel_fp();
+
+#ifdef CONFIG_ALTIVEC
+	if (cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC)
+		enable_kernel_altivec();
+#endif /* CONFIG_ALTIVEC */
+
+	return 0;
+}
+
+static int pmac_pm_finish(suspend_state_t state)
+{
+	printk(KERN_DEBUG "%s(%d)\n", __FUNCTION__, state);
+
+	/* Restore userland MMU context */
+	set_context(current->active_mm->context, current->active_mm->pgd);
+
+	return 0;
+}
+
+static struct pm_ops pmac_pm_ops = {
+	.pm_disk_mode	= PM_DISK_SHUTDOWN,
+	.prepare	= pmac_pm_prepare,
+	.enter		= pmac_pm_enter,
+	.finish		= pmac_pm_finish,
+};
+
+#endif /* CONFIG_SOFTWARE_SUSPEND */
 
 static int pmac_late_init(void)
 {
 	initializing = 0;
+#ifdef CONFIG_SOFTWARE_SUSPEND
+	pm_set_ops(&pmac_pm_ops);
+#endif /* CONFIG_SOFTWARE_SUSPEND */
 	return 0;
 }
 
diff -u -Naur linux-2.6.10.orig/drivers/ide/ppc/pmac.c linux-2.6.10/drivers/ide/ppc/pmac.c
--- linux-2.6.10.orig/drivers/ide/ppc/pmac.c	2004-12-24 22:33:59.000000000 +0100
+++ linux-2.6.10/drivers/ide/ppc/pmac.c	2005-01-04 14:21:32.000000000 +0100
@@ -32,6 +32,7 @@
 #include <linux/notifier.h>
 #include <linux/reboot.h>
 #include <linux/pci.h>
+#include <linux/pm.h>
 #include <linux/adb.h>
 #include <linux/pmu.h>
 #include <linux/scatterlist.h>
@@ -1360,7 +1361,7 @@
 	ide_hwif_t	*hwif = (ide_hwif_t *)dev_get_drvdata(&mdev->ofdev.dev);
 	int		rc = 0;
 
-	if (state != mdev->ofdev.dev.power.power_state && state >= 2) {
+	if (state != mdev->ofdev.dev.power.power_state && state == PM_SUSPEND_MEM) {
 		rc = pmac_ide_do_suspend(hwif);
 		if (rc == 0)
 			mdev->ofdev.dev.power.power_state = state;
@@ -1468,7 +1469,7 @@
 	ide_hwif_t	*hwif = (ide_hwif_t *)pci_get_drvdata(pdev);
 	int		rc = 0;
 	
-	if (state != pdev->dev.power.power_state && state >= 2) {
+	if (state != pdev->dev.power.power_state && state == PM_SUSPEND_MEM ) {
 		rc = pmac_ide_do_suspend(hwif);
 		if (rc == 0)
 			pdev->dev.power.power_state = state;
diff -u -Naur linux-2.6.10.orig/drivers/macintosh/Kconfig linux-2.6.10/drivers/macintosh/Kconfig
--- linux-2.6.10.orig/drivers/macintosh/Kconfig	2004-12-24 22:34:32.000000000 +0100
+++ linux-2.6.10/drivers/macintosh/Kconfig	2005-01-04 14:21:32.000000000 +0100
@@ -80,7 +80,7 @@
 
 config PMAC_PBOOK
 	bool "Power management support for PowerBooks"
-	depends on ADB_PMU
+	depends on PM && ADB_PMU
 	---help---
 	  This provides support for putting a PowerBook to sleep; it also
 	  enables media bay support.  Power management works on the
@@ -97,11 +97,6 @@
 	  have it autoloaded. The act of removing the module shuts down the
 	  sound hardware for more power savings.
 
-config PM
-	bool
-	depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
-	default y
-
 config PMAC_APM_EMU
 	tristate "APM emulation"
 	depends on PMAC_PBOOK
diff -u -Naur linux-2.6.10.orig/drivers/macintosh/therm_pm72.c linux-2.6.10/drivers/macintosh/therm_pm72.c
--- linux-2.6.10.orig/drivers/macintosh/therm_pm72.c	2004-12-24 22:35:23.000000000 +0100
+++ linux-2.6.10/drivers/macintosh/therm_pm72.c	2005-01-04 14:21:32.000000000 +0100
@@ -100,6 +100,7 @@
 #include <linux/spinlock.h>
 #include <linux/smp_lock.h>
 #include <linux/wait.h>
+#include <linux/suspend.h>
 #include <linux/reboot.h>
 #include <linux/kmod.h>
 #include <linux/i2c.h>
@@ -1318,6 +1319,11 @@
 	while (state == state_attached) {
 		unsigned long elapsed, start;
 
+		if (current->flags & PF_FREEZE) {
+			printk(KERN_INFO "therm_pm72: freezing thermostat\n");
+			refrigerator(PF_FREEZE);
+		}
+
 		start = jiffies;
 
 		down(&driver_lock);
diff -u -Naur linux-2.6.10.orig/drivers/macintosh/via-pmu.c linux-2.6.10/drivers/macintosh/via-pmu.c
--- linux-2.6.10.orig/drivers/macintosh/via-pmu.c	2004-12-24 22:35:28.000000000 +0100
+++ linux-2.6.10/drivers/macintosh/via-pmu.c	2005-01-04 14:21:32.000000000 +0100
@@ -43,6 +43,7 @@
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/device.h>
+#include <linux/sysdev.h>
 #include <linux/suspend.h>
 #include <linux/syscalls.h>
 #include <asm/prom.h>
@@ -2326,7 +2327,7 @@
 	/* Sync the disks. */
 	/* XXX It would be nice to have some way to ensure that
 	 * nobody is dirtying any new buffers while we wait. That
-	 * could be acheived using the refrigerator for processes
+	 * could be achieved using the refrigerator for processes
 	 * that swsusp uses
 	 */
 	sys_sync();
@@ -2379,7 +2380,6 @@
 
 	/* Wait for completion of async backlight requests */
 	while (!bright_req_1.complete || !bright_req_2.complete ||
-
 			!batt_req.complete)
 		pmu_poll();
 
@@ -3048,6 +3048,88 @@
 }
 #endif /* DEBUG_SLEEP */
 
+
+/* FIXME: This is a temporary set of callbacks to enable us
+ * to do suspend-to-disk.
+ */
+
+#ifdef CONFIG_PM
+
+static int pmu_sys_suspended = 0;
+
+static int pmu_sys_suspend(struct sys_device *sysdev, u32 state)
+{
+	if (state != PM_SUSPEND_DISK || pmu_sys_suspended)
+		return 0;
+
+	/* Suspend PMU event interrupts */
+	pmu_suspend();
+
+	pmu_sys_suspended = 1;
+	return 0;
+}
+
+static int pmu_sys_resume(struct sys_device *sysdev)
+{
+	struct adb_request req;
+
+	if (!pmu_sys_suspended)
+		return 0;
+
+	/* Tell PMU we are ready */
+	pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
+	pmu_wait_complete(&req);
+
+	/* Resume PMU event interrupts */
+	pmu_resume();
+
+	pmu_sys_suspended = 0;
+
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+static struct sysdev_class pmu_sysclass = {
+	set_kset_name("pmu"),
+};
+
+static struct sys_device device_pmu = {
+	.id		= 0,
+	.cls		= &pmu_sysclass,
+};
+
+static struct sysdev_driver driver_pmu = {
+#ifdef CONFIG_PM
+	.suspend	= &pmu_sys_suspend,
+	.resume		= &pmu_sys_resume,
+#endif /* CONFIG_PM */
+};
+
+static int __init init_pmu_sysfs(void)
+{
+	int rc;
+
+	rc = sysdev_class_register(&pmu_sysclass);
+	if (rc) {
+		printk(KERN_ERR "Failed registering PMU sys class\n");
+		return -ENODEV;
+	}
+	rc = sysdev_register(&device_pmu);
+	if (rc) {
+		printk(KERN_ERR "Failed registering PMU sys device\n");
+		return -ENODEV;
+	}
+	rc = sysdev_driver_register(&pmu_sysclass, &driver_pmu);
+	if (rc) {
+		printk(KERN_ERR "Failed registering PMU sys driver\n");
+		return -ENODEV;
+	}
+	return 0;
+}
+
+subsys_initcall(init_pmu_sysfs);
+
 EXPORT_SYMBOL(pmu_request);
 EXPORT_SYMBOL(pmu_poll);
 EXPORT_SYMBOL(pmu_poll_adb);
diff -u -Naur linux-2.6.10.orig/drivers/net/pcnet32.c linux-2.6.10/drivers/net/pcnet32.c
--- linux-2.6.10.orig/drivers/net/pcnet32.c	2004-12-24 22:34:29.000000000 +0100
+++ linux-2.6.10/drivers/net/pcnet32.c	2005-01-04 14:27:26.713281000 +0100
@@ -1429,26 +1429,33 @@
 	val |= 0x10;
     lp->a.write_csr (ioaddr, 124, val);
 
-    /* 24 Jun 2004 according AMD, in order to change the PHY,
-     * DANAS (or DISPM for 79C976) must be set; then select the speed,
-     * duplex, and/or enable auto negotiation, and clear DANAS */
-    if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) {
-	lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080);
-	/* disable Auto Negotiation, set 10Mpbs, HD */
-	val = lp->a.read_bcr(ioaddr, 32) & ~0xb8;
-	if (lp->options & PCNET32_PORT_FD)
-	    val |= 0x10;
-	if (lp->options & PCNET32_PORT_100)
-	    val |= 0x08;
-	lp->a.write_bcr (ioaddr, 32, val);
+    /* Allied Telesyn AT 2701 FX looses the link, so skip that */
+    if(lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT && 
+       (lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2700FX || 
+	lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX )) {
+    	printk(KERN_DEBUG "pcnet32: Skipping PHY selection.\n");
     } else {
-	if (lp->options & PCNET32_PORT_ASEL) {
-	    lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080);
-	    /* enable auto negotiate, setup, disable fd */
-	    val = lp->a.read_bcr(ioaddr, 32) & ~0x98;
-	    val |= 0x20;
-	    lp->a.write_bcr(ioaddr, 32, val);
-	}
+        /* 24 Jun 2004 according AMD, in order to change the PHY,
+         * DANAS (or DISPM for 79C976) must be set; then select the speed,
+         * duplex, and/or enable auto negotiation, and clear DANAS */
+        if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) {
+    	lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080);
+    	/* disable Auto Negotiation, set 10Mpbs, HD */
+    	val = lp->a.read_bcr(ioaddr, 32) & ~0xb8;
+    	if (lp->options & PCNET32_PORT_FD)
+    	    val |= 0x10;
+    	if (lp->options & PCNET32_PORT_100)
+    	    val |= 0x08;
+    	lp->a.write_bcr (ioaddr, 32, val);
+        } else {
+    	    if (lp->options & PCNET32_PORT_ASEL) {
+    	        lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080);
+    	        /* enable auto negotiate, setup, disable fd */
+    	        val = lp->a.read_bcr(ioaddr, 32) & ~0x98;
+    	        val |= 0x20;
+    	        lp->a.write_bcr(ioaddr, 32, val);
+    	    }
+        }
     }
 
 #ifdef DO_DXSUFLO
diff -u -Naur linux-2.6.10.orig/drivers/video/aty/radeon_pm.c linux-2.6.10/drivers/video/aty/radeon_pm.c
--- linux-2.6.10.orig/drivers/video/aty/radeon_pm.c	2004-12-24 22:35:18.000000000 +0100
+++ linux-2.6.10/drivers/video/aty/radeon_pm.c	2005-01-04 14:21:32.000000000 +0100
@@ -860,7 +860,9 @@
 	 * can properly take care of D3 ? Also, with swsusp, we
 	 * know we'll be rebooted, ...
 	 */
-
+#ifdef CONFIG_SOFTWARE_SUSPEND /* ...until the dust has settled */
+		return 0;
+#endif
 	printk(KERN_DEBUG "radeonfb: suspending to state: %d...\n", state);
 	
 	acquire_console_sem();
diff -u -Naur linux-2.6.10.orig/include/asm-ppc/param.h linux-2.6.10/include/asm-ppc/param.h
--- linux-2.6.10.orig/include/asm-ppc/param.h	2004-12-24 22:34:32.000000000 +0100
+++ linux-2.6.10/include/asm-ppc/param.h	2005-01-04 14:21:32.000000000 +0100
@@ -2,7 +2,7 @@
 #define _ASM_PPC_PARAM_H
 
 #ifdef __KERNEL__
-#define HZ		1000		/* internal timer frequency */
+#define HZ		(CONFIG_PPC_HZ)	/* internal timer frequency */
 #define USER_HZ		100		/* for user interfaces in "ticks" */
 #define CLOCKS_PER_SEC	(USER_HZ)	/* frequency at which times() counts */
 #endif /* __KERNEL__ */
diff -u -Naur linux-2.6.10.orig/include/asm-ppc/suspend.h linux-2.6.10/include/asm-ppc/suspend.h
--- linux-2.6.10.orig/include/asm-ppc/suspend.h	1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.10/include/asm-ppc/suspend.h	2005-01-04 14:21:32.000000000 +0100
@@ -0,0 +1,12 @@
+static inline int arch_prepare_suspend(void)
+{
+	return 0;
+}
+
+static inline void save_processor_state(void)
+{
+}
+
+static inline void restore_processor_state(void)
+{
+}
diff -u -Naur linux-2.6.10.orig/include/asm-ppc/system.h linux-2.6.10/include/asm-ppc/system.h
--- linux-2.6.10.orig/include/asm-ppc/system.h	2004-12-24 22:34:32.000000000 +0100
+++ linux-2.6.10/include/asm-ppc/system.h	2005-01-04 14:21:32.000000000 +0100
@@ -74,6 +74,7 @@
 extern void pmac_find_display(void);
 extern void giveup_fpu(struct task_struct *);
 extern void enable_kernel_fp(void);
+extern void enable_kernel_altivec(void);
 extern void giveup_altivec(struct task_struct *);
 extern void load_up_altivec(struct task_struct *);
 extern void giveup_spe(struct task_struct *);
diff -u -Naur linux-2.6.10.orig/include/linux/pci_ids.h linux-2.6.10/include/linux/pci_ids.h
--- linux-2.6.10.orig/include/linux/pci_ids.h	2004-12-24 22:35:50.000000000 +0100
+++ linux-2.6.10/include/linux/pci_ids.h	2005-01-04 14:26:39.543281000 +0100
@@ -1631,6 +1631,11 @@
 #define PCI_DEVICE_ID_OPTIBASE_VPLEXCC	0x2120
 #define PCI_DEVICE_ID_OPTIBASE_VQUEST	0x2130
 
+/* Allied Telesyn */
+#define PCI_VENDOR_ID_AT    		0x1259
+#define PCI_SUBDEVICE_ID_AT_2701FX	0x2703
+#define PCI_SUBDEVICE_ID_AT_2700FX	0x2701
+
 #define PCI_VENDOR_ID_ESS		0x125d
 #define PCI_DEVICE_ID_ESS_ESS1968	0x1968
 #define PCI_DEVICE_ID_ESS_AUDIOPCI	0x1969
diff -u -Naur linux-2.6.10.orig/include/linux/reboot.h linux-2.6.10/include/linux/reboot.h
--- linux-2.6.10.orig/include/linux/reboot.h	2004-12-24 22:35:50.000000000 +0100
+++ linux-2.6.10/include/linux/reboot.h	2005-01-04 14:21:32.000000000 +0100
@@ -42,6 +42,8 @@
 extern int register_reboot_notifier(struct notifier_block *);
 extern int unregister_reboot_notifier(struct notifier_block *);
 
+/* For use by swsusp only */
+extern struct notifier_block *reboot_notifier_list;
 
 /*
  * Architecture-specific implementations of sys_reboot commands.
diff -u -Naur linux-2.6.10.orig/include/linux/suspend.h linux-2.6.10/include/linux/suspend.h
--- linux-2.6.10.orig/include/linux/suspend.h	2004-12-24 22:34:27.000000000 +0100
+++ linux-2.6.10/include/linux/suspend.h	2005-01-04 14:21:32.000000000 +0100
@@ -1,7 +1,7 @@
 #ifndef _LINUX_SWSUSP_H
 #define _LINUX_SWSUSP_H
 
-#ifdef CONFIG_X86
+#if defined(CONFIG_X86) || defined(CONFIG_PPC32)
 #include <asm/suspend.h>
 #endif
 #include <linux/swap.h>
diff -u -Naur linux-2.6.10.orig/kernel/power/disk.c linux-2.6.10/kernel/power/disk.c
--- linux-2.6.10.orig/kernel/power/disk.c	2004-12-24 22:33:50.000000000 +0100
+++ linux-2.6.10/kernel/power/disk.c	2005-01-04 14:21:32.000000000 +0100
@@ -17,6 +17,7 @@
 #include <linux/delay.h>
 #include <linux/fs.h>
 #include <linux/device.h>
+#include <linux/reboot.h>
 #include "power.h"
 
 
@@ -48,14 +49,15 @@
 	unsigned long flags;
 	int error = 0;
 
-	local_irq_save(flags);
 	switch(mode) {
 	case PM_DISK_PLATFORM:
-		device_power_down(PM_SUSPEND_DISK);
+	    	local_irq_save(flags);
 		error = pm_ops->enter(PM_SUSPEND_DISK);
+		local_irq_restore(flags);
 		break;
 	case PM_DISK_SHUTDOWN:
 		printk("Powering off system\n");
+    		notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
 		device_shutdown();
 		machine_power_off();
 		break;
diff -u -Naur linux-2.6.10.orig/kernel/power/swsusp.c linux-2.6.10/kernel/power/swsusp.c
--- linux-2.6.10.orig/kernel/power/swsusp.c	2004-12-24 22:34:27.000000000 +0100
+++ linux-2.6.10/kernel/power/swsusp.c	2005-01-04 14:21:34.000000000 +0100
@@ -862,16 +862,18 @@
 	if ((error = arch_prepare_suspend()))
 		return error;
 	local_irq_disable();
+	device_power_down(PM_SUSPEND_DISK);
 	save_processor_state();
 	error = swsusp_arch_suspend();
 	/* Restore control flow magically appears here */
 	restore_processor_state();
 	restore_highmem();
+	device_power_up();
 	local_irq_enable();
 	return error;
 }
 
-
+#if 0
 asmlinkage int swsusp_restore(void)
 {
 	BUG_ON (nr_copy_pages_check != nr_copy_pages);
@@ -881,11 +883,13 @@
 	__flush_tlb_global();
 	return 0;
 }
+#endif
 
 int swsusp_resume(void)
 {
 	int error;
 	local_irq_disable();
+ 	device_power_down(PM_SUSPEND_DISK);
 	/* We'll ignore saved state, but this gets preempt count (etc) right */
 	save_processor_state();
 	error = swsusp_arch_resume();
@@ -895,6 +899,7 @@
 	BUG_ON(!error);
 	restore_processor_state();
 	restore_highmem();
+ 	device_power_up();
 	local_irq_enable();
 	return error;
 }
@@ -1186,7 +1191,7 @@
 		return -ENOMEM;
 	pagedir_nosave = (struct pbe *)addr;
 
-	pr_debug("pmdisk: Reading pagedir (%d Pages)\n",n);
+	pr_debug("swsusp: Reading pagedir (%d Pages)\n",n);
 
 	for (i = 0; i < n && !error; i++, addr += PAGE_SIZE) {
 		unsigned long offset = swp_offset(swsusp_info.pagedir[i]);
@@ -1216,7 +1221,7 @@
 }
 
 /**
- *	pmdisk_read - Read saved image from swap.
+ *	swsusp_read - Read saved image from swap.
  */
 
 int __init swsusp_read(void)
@@ -1240,6 +1245,6 @@
 	if (!error)
 		pr_debug("Reading resume file was successful\n");
 	else
-		pr_debug("pmdisk: Error %d resuming\n", error);
+		pr_debug("swsusp: Error %d resuming\n", error);
 	return error;
 }
diff -u -Naur linux-2.6.10.orig/kernel/sys.c linux-2.6.10/kernel/sys.c
--- linux-2.6.10.orig/kernel/sys.c	2004-12-24 22:33:59.000000000 +0100
+++ linux-2.6.10/kernel/sys.c	2005-01-04 14:21:34.000000000 +0100
@@ -87,7 +87,7 @@
  *	and the like. 
  */
 
-static struct notifier_block *reboot_notifier_list;
+struct notifier_block *reboot_notifier_list;
 rwlock_t notifier_lock = RW_LOCK_UNLOCKED;
 
 /**
diff -u -Naur linux-2.6.10.orig/sound/ppc/pmac.c linux-2.6.10/sound/ppc/pmac.c
--- linux-2.6.10.orig/sound/ppc/pmac.c	2004-12-24 22:35:49.000000000 +0100
+++ linux-2.6.10/sound/ppc/pmac.c	2005-01-04 14:21:34.000000000 +0100
@@ -50,8 +50,8 @@
 	44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
 };
 /* fixed frequency table for tumbler */
-static int tumbler_freqs[1] = {
-	44100
+static int tumbler_freqs[2] = {
+	48000, 44100
 };
 
 /*
@@ -488,12 +488,14 @@
 	snd_pcm_runtime_t *runtime = subs->runtime;
 	int i, j, fflags;
 	static int typical_freqs[] = {
+		48000,
 		44100,
 		22050,
 		11025,
 		0,
 	};
 	static int typical_freq_flags[] = {
+		SNDRV_PCM_RATE_48000,
 		SNDRV_PCM_RATE_44100,
 		SNDRV_PCM_RATE_22050,
 		SNDRV_PCM_RATE_11025,
@@ -647,7 +649,7 @@
 
 	pcm->private_data = chip;
 	pcm->private_free = pmac_pcm_free;
-	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
+	pcm->info_flags = 0;
 	strcpy(pcm->name, chip->card->shortname);
 	chip->pcm = pcm;
 
diff -u -Naur linux-2.6.10.orig/sound/ppc/tumbler.c linux-2.6.10/sound/ppc/tumbler.c
--- linux-2.6.10.orig/sound/ppc/tumbler.c	2004-12-24 22:33:49.000000000 +0100
+++ linux-2.6.10/sound/ppc/tumbler.c	2005-01-04 14:21:34.000000000 +0100
@@ -767,6 +767,12 @@
 	DEFINE_MONO("Tone Control - Treble", treble),
 	DEFINE_MONO("PCM Playback Volume", pcm),
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	  .name = "DRC Switch",
+	  .info = snd_pmac_boolean_mono_info,
+	  .get = tumbler_get_drc_switch,
+	  .put = tumbler_put_drc_switch
+	},
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	  .name = "DRC Range",
 	  .info = tumbler_info_drc_value,
 	  .get = tumbler_get_drc_value,
@@ -793,6 +799,12 @@
 	DEFINE_SNAPPER_MONO("Tone Control - Bass", bass),
 	DEFINE_SNAPPER_MONO("Tone Control - Treble", treble),
 	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	  .name = "DRC Switch",
+	  .info = snd_pmac_boolean_mono_info,
+	  .get = tumbler_get_drc_switch,
+	  .put = tumbler_put_drc_switch
+	},
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	  .name = "DRC Range",
 	  .info = tumbler_info_drc_value,
 	  .get = tumbler_get_drc_value,
@@ -822,14 +834,6 @@
 	.put = tumbler_put_mute_switch,
 	.private_value = TUMBLER_MUTE_AMP,
 };
-static snd_kcontrol_new_t tumbler_drc_sw __initdata = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "DRC Switch",
-	.info = snd_pmac_boolean_mono_info,
-	.get = tumbler_get_drc_switch,
-	.put = tumbler_put_drc_switch
-};
-
 
 #ifdef PMAC_SUPPORT_AUTOMUTE
 /*
@@ -851,29 +855,6 @@
 	}
 }
 
-static struct work_struct device_change;
-
-static void
-device_change_handler(void *self)
-{
-	pmac_t *chip = (pmac_t*) self;
-	pmac_tumbler_t *mix;
-
-	if (!chip)
-		return;
-
-	mix = chip->mixer_data;
-
-	/* first set the DRC so the speaker do not explode -ReneR */
-	if (chip->model == PMAC_TUMBLER)
-		tumbler_set_drc(mix);
-	else
-		snapper_set_drc(mix);
-
-	/* reset the master volume so the correct amplification is applied */
-	tumbler_set_master_volume(mix);
-}
-
 static void tumbler_update_automute(pmac_t *chip, int do_notify)
 {
 	if (chip->auto_mute) {
@@ -883,25 +864,14 @@
 			/* mute speaker */
 			check_mute(chip, &mix->amp_mute, 1, do_notify, chip->speaker_sw_ctl);
 			check_mute(chip, &mix->hp_mute, 0, do_notify, chip->master_sw_ctl);
-			mix->drc_enable = 0;
-
 		} else {
 			/* unmute speaker */
 			check_mute(chip, &mix->amp_mute, 0, do_notify, chip->speaker_sw_ctl);
 			check_mute(chip, &mix->hp_mute, 1, do_notify, chip->master_sw_ctl);
-			mix->drc_enable = 1;
 		}
-		if (do_notify) {
+		if (do_notify)
 			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
 				       &chip->hp_detect_ctl->id);
-			snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
-			               &chip->drc_sw_ctl->id);
-		}
-
-		/* finally we need to schedule an update of the mixer values
-		   (master and DRC are enough for now) -ReneR */
-		schedule_work(&device_change);
-
 	}
 }
 #endif /* PMAC_SUPPORT_AUTOMUTE */
@@ -1028,7 +998,7 @@
 	}
 	tumbler_set_master_volume(mix);
 	if (chip->update_automute)
-		chip->update_automute(chip, 0);
+		chip->update_automute(chip, 1);
 }
 #endif
 
@@ -1152,17 +1122,11 @@
 	chip->speaker_sw_ctl = snd_ctl_new1(&tumbler_speaker_sw, chip);
 	if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0)
 		return err;
-	chip->drc_sw_ctl = snd_ctl_new1(&tumbler_drc_sw, chip);
-	if ((err = snd_ctl_add(chip->card, chip->drc_sw_ctl)) < 0)
-		return err;
-
 
 #ifdef CONFIG_PMAC_PBOOK
 	chip->resume = tumbler_resume;
 #endif
 
-	INIT_WORK(&device_change, device_change_handler, (void *)chip);
-
 #ifdef PMAC_SUPPORT_AUTOMUTE
 	if (mix->headphone_irq >=0 && (err = snd_pmac_add_automute(chip)) < 0)
 		return err;

Reply to: