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

Re: iBook 2.2: Kernel 2.6.8 and beep (PC Speaker)?



Sven Luther <sven.luther@wanadoo.fr> wrote:

Hi Sven,

>> Use filterdiff (patchutils) to filter the changes made to sound/ppc/*,
>> and here's your diff.
>
> I am over busy with other stuff right now, but would you care to do this and
> send me the patch (or fill a bug report) ?

Here it is. beep.patch contains everything related to the beep
support. chips.patch contains the other changes to the files in
sound/ppc, which are bugfixes and new features for the awacs, daca,
tumbler and burgundy chips.

The changes in chips.patch are minimal, you could apply them too
without any problem.

I didn't try to build with the patches applied (lacking time), but
reading the diff there's nothing that should break.

JB.

-- 
 Julien BLACHE - Debian & GNU/Linux Developer - <jblache@debian.org> 
 
 Public key available on <http://www.jblache.org> - KeyID: F5D6 5169 
 GPG Fingerprint : 935A 79F1 C8B3 3521 FD62 7CC7 CD61 4FD7 F5D6 5169 

--- linux-2.5-plain/sound/ppc/beep.c	1970-01-01 01:00:00.000000000 +0100
+++ linux-sound-plain/sound/ppc/beep.c	2004-08-26 21:17:10.000000000 +0200
@@ -0,0 +1,262 @@
+/*
+ * Beep using pcm
+ *
+ * Copyright (c) by Takashi Iwai <tiwai@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <sound/driver.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <sound/core.h>
+#include <sound/control.h>
+#include "pmac.h"
+
+struct snd_pmac_beep {
+	int running;	/* boolean */
+	int volume;	/* mixer volume: 0-100 */
+	int volume_play;	/* currently playing volume */
+	int hz;
+	int nsamples;
+	short *buf;		/* allocated wave buffer */
+	unsigned long addr;	/* physical address of buffer */
+	struct input_dev dev;
+};
+
+/*
+ * stop beep if running
+ */
+void snd_pmac_beep_stop(pmac_t *chip)
+{
+	pmac_beep_t *beep = chip->beep;
+	if (beep && beep->running) {
+		beep->running = 0;
+		snd_pmac_beep_dma_stop(chip);
+	}
+}
+
+/*
+ * Stuff for outputting a beep.  The values range from -327 to +327
+ * so we can multiply by an amplitude in the range 0..100 to get a
+ * signed short value to put in the output buffer.
+ */
+static short beep_wform[256] = {
+	0,	40,	79,	117,	153,	187,	218,	245,
+	269,	288,	304,	316,	323,	327,	327,	324,
+	318,	310,	299,	288,	275,	262,	249,	236,
+	224,	213,	204,	196,	190,	186,	183,	182,
+	182,	183,	186,	189,	192,	196,	200,	203,
+	206,	208,	209,	209,	209,	207,	204,	201,
+	197,	193,	188,	183,	179,	174,	170,	166,
+	163,	161,	160,	159,	159,	160,	161,	162,
+	164,	166,	168,	169,	171,	171,	171,	170,
+	169,	167,	163,	159,	155,	150,	144,	139,
+	133,	128,	122,	117,	113,	110,	107,	105,
+	103,	103,	103,	103,	104,	104,	105,	105,
+	105,	103,	101,	97,	92,	86,	78,	68,
+	58,	45,	32,	18,	3,	-11,	-26,	-41,
+	-55,	-68,	-79,	-88,	-95,	-100,	-102,	-102,
+	-99,	-93,	-85,	-75,	-62,	-48,	-33,	-16,
+	0,	16,	33,	48,	62,	75,	85,	93,
+	99,	102,	102,	100,	95,	88,	79,	68,
+	55,	41,	26,	11,	-3,	-18,	-32,	-45,
+	-58,	-68,	-78,	-86,	-92,	-97,	-101,	-103,
+	-105,	-105,	-105,	-104,	-104,	-103,	-103,	-103,
+	-103,	-105,	-107,	-110,	-113,	-117,	-122,	-128,
+	-133,	-139,	-144,	-150,	-155,	-159,	-163,	-167,
+	-169,	-170,	-171,	-171,	-171,	-169,	-168,	-166,
+	-164,	-162,	-161,	-160,	-159,	-159,	-160,	-161,
+	-163,	-166,	-170,	-174,	-179,	-183,	-188,	-193,
+	-197,	-201,	-204,	-207,	-209,	-209,	-209,	-208,
+	-206,	-203,	-200,	-196,	-192,	-189,	-186,	-183,
+	-182,	-182,	-183,	-186,	-190,	-196,	-204,	-213,
+	-224,	-236,	-249,	-262,	-275,	-288,	-299,	-310,
+	-318,	-324,	-327,	-327,	-323,	-316,	-304,	-288,
+	-269,	-245,	-218,	-187,	-153,	-117,	-79,	-40,
+};
+
+#define BEEP_SRATE	22050	/* 22050 Hz sample rate */
+#define BEEP_BUFLEN	512
+#define BEEP_VOLUME	15	/* 0 - 100 */
+
+static int snd_pmac_beep_event(struct input_dev *dev, unsigned int type, unsigned int code, int hz)
+{
+	pmac_t *chip;
+	pmac_beep_t *beep;
+	unsigned long flags;
+	int beep_speed = 0;
+	int srate;
+	int period, ncycles, nsamples;
+	int i, j, f;
+	short *p;
+
+	if (type != EV_SND)
+		return -1;
+
+	switch (code) {
+	case SND_BELL: if (hz) hz = 1000;
+	case SND_TONE: break;
+	default: return -1;
+	}
+
+	chip = dev->private;
+	if (! chip || (beep = chip->beep) == NULL)
+		return -1;
+
+	if (! hz) {
+		spin_lock_irqsave(&chip->reg_lock, flags);
+		if (beep->running)
+			snd_pmac_beep_stop(chip);
+		spin_unlock_irqrestore(&chip->reg_lock, flags);
+		return 0;
+	}
+
+	beep_speed = snd_pmac_rate_index(chip, &chip->playback, BEEP_SRATE);
+	srate = chip->freq_table[beep_speed];
+
+	if (hz <= srate / BEEP_BUFLEN || hz > srate / 2)
+		hz = 1000;
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	if (chip->playback.running || chip->capture.running || beep->running) {
+		spin_unlock_irqrestore(&chip->reg_lock, flags);
+		return 0;
+	}
+	beep->running = 1;
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+
+	if (hz == beep->hz && beep->volume == beep->volume_play) {
+		nsamples = beep->nsamples;
+	} else {
+		period = srate * 256 / hz;	/* fixed point */
+		ncycles = BEEP_BUFLEN * 256 / period;
+		nsamples = (period * ncycles) >> 8;
+		f = ncycles * 65536 / nsamples;
+		j = 0;
+		p = beep->buf;
+		for (i = 0; i < nsamples; ++i, p += 2) {
+			p[0] = p[1] = beep_wform[j >> 8] * beep->volume;
+			j = (j + f) & 0xffff;
+		}
+		beep->hz = hz;
+		beep->volume_play = beep->volume;
+		beep->nsamples = nsamples;
+	}
+
+	spin_lock_irqsave(&chip->reg_lock, flags);
+	snd_pmac_beep_dma_start(chip, beep->nsamples * 4, beep->addr, beep_speed);
+	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	return 0;
+}
+
+/*
+ * beep volume mixer
+ */
+
+#define chip_t pmac_t
+
+static int snd_pmac_info_beep(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 100;
+	return 0;
+}
+
+static int snd_pmac_get_beep(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	pmac_t *chip = snd_kcontrol_chip(kcontrol);
+	snd_assert(chip->beep, return -ENXIO);
+	ucontrol->value.integer.value[0] = chip->beep->volume;
+	return 0;
+}
+
+static int snd_pmac_put_beep(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
+{
+	pmac_t *chip = snd_kcontrol_chip(kcontrol);
+	int oval;
+	snd_assert(chip->beep, return -ENXIO);
+	oval = chip->beep->volume;
+	chip->beep->volume = ucontrol->value.integer.value[0];
+	return oval != chip->beep->volume;
+}
+
+static snd_kcontrol_new_t snd_pmac_beep_mixer = {
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "Beep Playback Volume",
+	.info = snd_pmac_info_beep,
+	.get = snd_pmac_get_beep,
+	.put = snd_pmac_put_beep,
+};
+
+/* Initialize beep stuff */
+int __init snd_pmac_attach_beep(pmac_t *chip)
+{
+	pmac_beep_t *beep;
+	int err;
+
+	beep = kmalloc(sizeof(*beep), GFP_KERNEL);
+	if (! beep)
+		return -ENOMEM;
+
+	memset(beep, 0, sizeof(*beep));
+	beep->buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
+	if (! beep->buf) {
+		kfree(beep);
+		return -ENOMEM;
+	}
+	beep->addr = virt_to_bus(beep->buf);
+
+	beep->dev.evbit[0] = BIT(EV_SND);
+	beep->dev.sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+	beep->dev.event = snd_pmac_beep_event;
+	beep->dev.private = chip;
+
+	/* FIXME: set more better values */
+	beep->dev.name = "PowerMac Beep";
+	beep->dev.phys = "powermac/beep";
+	beep->dev.id.bustype = BUS_ADB;
+	beep->dev.id.vendor = 0x001f;
+	beep->dev.id.product = 0x0001;
+	beep->dev.id.version = 0x0100;
+
+	beep->volume = BEEP_VOLUME;
+	beep->running = 0;
+	if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_beep_mixer, chip))) < 0) {
+		kfree(beep->buf);
+		kfree(beep);
+		return err;
+	}
+
+	chip->beep = beep;
+	input_register_device(&beep->dev);
+
+	return 0;
+}
+
+void snd_pmac_detach_beep(pmac_t *chip)
+{
+	if (chip->beep) {
+		input_unregister_device(&chip->beep->dev);
+		kfree(chip->beep->buf);
+		kfree(chip->beep);
+		chip->beep = NULL;
+	}
+}
--- linux-2.5-plain/sound/ppc/Kconfig	2004-08-26 21:01:50.000000000 +0200
+++ linux-sound-plain/sound/ppc/Kconfig	2004-08-26 21:16:11.000000000 +0200
@@ -6,9 +6,12 @@
 comment "ALSA PowerMac requires I2C"
 	depends on SND && I2C=n
 
+comment "ALSA PowerMac requires INPUT"
+	depends on SND && INPUT=n
+
 config SND_POWERMAC
 	tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)"
-	depends on SND && I2C
+	depends on SND && I2C && INPUT
 	select SND_PCM
 
 endmenu
--- linux-2.5-plain/sound/ppc/Makefile	2004-08-26 21:01:48.000000000 +0200
+++ linux-sound-plain/sound/ppc/Makefile	2004-08-26 21:16:09.000000000 +0200
@@ -3,7 +3,7 @@
 # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz>
 #
 
-snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o
+snd-powermac-objs := powermac.o pmac.o awacs.o burgundy.o daca.o tumbler.o keywest.o beep.o
 
 # Toplevel Module Dependency
 obj-$(CONFIG_SND_POWERMAC) += snd-powermac.o
--- linux-2.5-plain/sound/ppc/pmac.c	2004-08-26 21:05:32.000000000 +0200
+++ linux-sound-plain/sound/ppc/pmac.c	2004-08-26 21:20:59.000000000 +0200
@@ -36,8 +36,6 @@
 #include <asm/feature.h>
 #endif
 
-#define chip_t pmac_t
-
 
 #if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
 static int snd_pmac_register_sleep_notifier(pmac_t *chip);
@@ -52,8 +50,8 @@
 	44100, 29400, 22050, 17640, 14700, 11025, 8820, 7350
 };
 /* fixed frequency table for tumbler */
-static int tumbler_freqs[2] = {
-	48000, 44100
+static int tumbler_freqs[1] = {
+	44100
 };
 
 /*
@@ -86,7 +84,7 @@
  * look up frequency table
  */
 
-static unsigned int snd_pmac_rate_index(pmac_t *chip, pmac_stream_t *rec, unsigned int rate)
+unsigned int snd_pmac_rate_index(pmac_t *chip, pmac_stream_t *rec, unsigned int rate)
 {
 	int i, ok, found;
 
@@ -203,7 +201,6 @@
 {
 	int i;
 	volatile struct dbdma_cmd *cp;
-	unsigned long flags;
 	snd_pcm_runtime_t *runtime = subs->runtime;
 	int rate_index;
 	long offset;
@@ -226,15 +223,17 @@
 	/* We really want to execute a DMA stop command, after the AWACS
 	 * is initialized.
 	 * For reasons I don't understand, it stops the hissing noise
-	 * common to many PowerBook G3 systems (like mine :-).
+	 * common to many PowerBook G3 systems and random noise otherwise
+	 * captured on iBook2's about every third time. -ReneR
 	 */
-	spin_lock_irqsave(&chip->reg_lock, flags);
+	spin_lock_irq(&chip->reg_lock);
 	snd_pmac_dma_stop(rec);
-	if (rec->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		st_le16(&chip->extra_dma.cmds->command, DBDMA_STOP);
-		snd_pmac_dma_set_command(rec, &chip->extra_dma);
-		snd_pmac_dma_run(rec, RUN);
-	}
+	st_le16(&chip->extra_dma.cmds->command, DBDMA_STOP);
+	snd_pmac_dma_set_command(rec, &chip->extra_dma);
+	snd_pmac_dma_run(rec, RUN);
+	spin_unlock_irq(&chip->reg_lock);
+	mdelay(5);
+	spin_lock_irq(&chip->reg_lock);
 	/* continuous DMA memory type doesn't provide the physical address,
 	 * so we need to resolve the address here...
 	 */
@@ -252,7 +251,7 @@
 
 	snd_pmac_dma_stop(rec);
 	snd_pmac_dma_set_command(rec, &rec->cmd);
-	spin_unlock_irqrestore(&chip->reg_lock, flags);
+	spin_unlock_irq(&chip->reg_lock);
 
 	return 0;
 }
@@ -264,7 +263,6 @@
 static int snd_pmac_pcm_trigger(pmac_t *chip, pmac_stream_t *rec,
 				snd_pcm_substream_t *subs, int cmd)
 {
-	unsigned long flags;
 	volatile struct dbdma_cmd *cp;
 	int i, command;
 
@@ -275,7 +273,7 @@
 			return -EBUSY;
 		command = (subs->stream == SNDRV_PCM_STREAM_PLAYBACK ?
 			   OUTPUT_MORE : INPUT_MORE) + INTR_ALWAYS;
-		spin_lock_irqsave(&chip->reg_lock, flags);
+		spin_lock(&chip->reg_lock);
 		snd_pmac_beep_stop(chip);
 		snd_pmac_pcm_set_format(chip);
 		for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
@@ -284,18 +282,18 @@
 		(void)in_le32(&rec->dma->status);
 		snd_pmac_dma_run(rec, RUN|WAKE);
 		rec->running = 1;
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
+		spin_unlock(&chip->reg_lock);
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
-		spin_lock_irqsave(&chip->reg_lock, flags);
+		spin_lock(&chip->reg_lock);
 		rec->running = 0;
 		/*printk("stopped!!\n");*/
 		snd_pmac_dma_stop(rec);
 		for (i = 0, cp = rec->cmd.cmds; i < rec->nperiods; i++, cp++)
 			out_le16(&cp->command, DBDMA_STOP);
-		spin_unlock_irqrestore(&chip->reg_lock, flags);
+		spin_unlock(&chip->reg_lock);
 		break;
 
 	default:
@@ -490,14 +488,12 @@
 	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,
@@ -651,7 +647,7 @@
 
 	pcm->private_data = chip;
 	pcm->private_free = pmac_pcm_free;
-	pcm->info_flags = 0;
+	pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX;
 	strcpy(pcm->name, chip->card->shortname);
 	chip->pcm = pcm;
 
@@ -683,12 +679,41 @@
 
 
 /*
+ * handling beep
+ */
+void snd_pmac_beep_dma_start(pmac_t *chip, int bytes, unsigned long addr, int speed)
+{
+	pmac_stream_t *rec = &chip->playback;
+
+	snd_pmac_dma_stop(rec);
+	st_le16(&chip->extra_dma.cmds->req_count, bytes);
+	st_le16(&chip->extra_dma.cmds->xfer_status, 0);
+	st_le32(&chip->extra_dma.cmds->cmd_dep, chip->extra_dma.addr);
+	st_le32(&chip->extra_dma.cmds->phy_addr, addr);
+	st_le16(&chip->extra_dma.cmds->command, OUTPUT_MORE + BR_ALWAYS);
+	out_le32(&chip->awacs->control,
+		 (in_le32(&chip->awacs->control) & ~0x1f00)
+		 | (speed << 8));
+	out_le32(&chip->awacs->byteswap, 0);
+	snd_pmac_dma_set_command(rec, &chip->extra_dma);
+	snd_pmac_dma_run(rec, RUN);
+}
+
+void snd_pmac_beep_dma_stop(pmac_t *chip)
+{
+	snd_pmac_dma_stop(&chip->playback);
+	st_le16(&chip->extra_dma.cmds->command, DBDMA_STOP);
+	snd_pmac_pcm_set_format(chip); /* reset format */
+}
+
+
+/*
  * interrupt handlers
  */
 static irqreturn_t
 snd_pmac_tx_intr(int irq, void *devid, struct pt_regs *regs)
 {
-	pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE);
+	pmac_t *chip = devid;
 	snd_pmac_pcm_update(chip, &chip->playback);
 	return IRQ_HANDLED;
 }
@@ -697,7 +722,7 @@
 static irqreturn_t
 snd_pmac_rx_intr(int irq, void *devid, struct pt_regs *regs)
 {
-	pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE);
+	pmac_t *chip = devid;
 	snd_pmac_pcm_update(chip, &chip->capture);
 	return IRQ_HANDLED;
 }
@@ -706,7 +731,7 @@
 static irqreturn_t
 snd_pmac_ctrl_intr(int irq, void *devid, struct pt_regs *regs)
 {
-	pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE);
+	pmac_t *chip = devid;
 	int ctrl = in_le32(&chip->awacs->control);
 
 	/*printk("pmac: control interrupt.. 0x%x\n", ctrl);*/
@@ -776,6 +801,8 @@
 	if (chip->mixer_free)
 		chip->mixer_free(chip);
 
+	snd_pmac_detach_beep(chip);
+
 	/* release resources */
 	if (chip->irq >= 0)
 		free_irq(chip->irq, (void*)chip);
@@ -802,7 +829,7 @@
 				release_OF_resource(chip->node, i);
 		}
 	}
-	snd_magic_kfree(chip);
+	kfree(chip);
 	return 0;
 }
 
@@ -812,7 +839,7 @@
  */
 static int snd_pmac_dev_free(snd_device_t *device)
 {
-	pmac_t *chip = snd_magic_cast(pmac_t, device->device_data, return -ENXIO);
+	pmac_t *chip = device->device_data;
 	return snd_pmac_free(chip);
 }
 
@@ -862,7 +889,7 @@
 	chip->can_byte_swap = 1;
 	chip->can_duplex = 1;
 	chip->can_capture = 1;
-	chip->num_freqs = 8;
+	chip->num_freqs = ARRAY_SIZE(awacs_freqs);
 	chip->freq_table = awacs_freqs;
 
 	chip->control_mask = MASK_IEPC | MASK_IEE | 0x11; /* default */
@@ -920,14 +947,14 @@
 		chip->can_capture = 0;  /* no capture */
 		chip->can_duplex = 0;
 		// chip->can_byte_swap = 0; /* FIXME: check this */
-		chip->num_freqs = 2;
+		chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
 		chip->freq_table = tumbler_freqs;
 		chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
 	}
 	if (device_is_compatible(sound, "snapper")) {
 		chip->model = PMAC_SNAPPER;
 		// chip->can_byte_swap = 0; /* FIXME: check this */
-		chip->num_freqs = 2;
+		chip->num_freqs = ARRAY_SIZE(tumbler_freqs);
 		chip->freq_table = tumbler_freqs;
 		chip->control_mask = MASK_IEPC | 0x11; /* disable IEE */
 	}
@@ -1069,7 +1096,7 @@
 	snd_runtime_check(chip_return, return -EINVAL);
 	*chip_return = NULL;
 
-	chip = snd_magic_kcalloc(pmac_t, 0, GFP_KERNEL);
+	chip = kcalloc(1, sizeof(*chip), GFP_KERNEL);
 	if (chip == NULL)
 		return -ENOMEM;
 	chip->card = card;
@@ -1206,7 +1233,7 @@
 
 static int snd_pmac_suspend(snd_card_t *card, unsigned int state)
 {
-	pmac_t *chip = snd_magic_cast(pmac_t, card->pm_private_data, return -EINVAL);
+	pmac_t *chip = card->pm_private_data;
 	unsigned long flags;
 
 	if (chip->suspend)
@@ -1228,7 +1255,7 @@
 
 static int snd_pmac_resume(snd_card_t *card, unsigned int state)
 {
-	pmac_t *chip = snd_magic_cast(pmac_t, card->pm_private_data, return -EINVAL);
+	pmac_t *chip = card->pm_private_data;
 
 	snd_pmac_sound_feature(chip, 1);
 	if (chip->resume)
--- linux-2.5-plain/sound/ppc/pmac.h	2004-08-26 21:03:12.000000000 +0200
+++ linux-sound-plain/sound/ppc/pmac.h	2004-08-26 21:18:00.000000000 +0200
@@ -84,7 +84,7 @@
 
 	snd_pcm_substream_t *substream;
 
-	unsigned int cur_freqs;		/* currently available frequences */
+	unsigned int cur_freqs;		/* currently available frequencies */
 	unsigned int cur_formats;	/* currently available formats */
 };
 
@@ -155,6 +155,7 @@
 	void (*mixer_free)(pmac_t *);
 	snd_kcontrol_t *master_sw_ctl;
 	snd_kcontrol_t *speaker_sw_ctl;
+	snd_kcontrol_t *drc_sw_ctl;	/* only used for tumbler -ReneR */
 	snd_kcontrol_t *hp_detect_ctl;
 
 	/* lowlevel callbacks */
@@ -173,6 +174,12 @@
 int snd_pmac_new(snd_card_t *card, pmac_t **chip_return);
 int snd_pmac_pcm_new(pmac_t *chip);
 int snd_pmac_attach_beep(pmac_t *chip);
+void snd_pmac_detach_beep(pmac_t *chip);
+void snd_pmac_beep_stop(pmac_t *chip);
+unsigned int snd_pmac_rate_index(pmac_t *chip, pmac_stream_t *rec, unsigned int rate);
+
+void snd_pmac_beep_dma_start(pmac_t *chip, int bytes, unsigned long addr, int speed);
+void snd_pmac_beep_dma_stop(pmac_t *chip);
 
 /* initialize mixer */
 int snd_pmac_awacs_init(pmac_t *chip);
@@ -206,9 +213,4 @@
 	schedule_timeout(((msec) * HZ + 999) / 1000);\
 } while (0)
 
-#ifndef PMAC_SUPPORT_PCM_BEEP
-#define snd_pmac_attach_beep(chip) 0
-#define snd_pmac_beep_stop(chip)  /**/
-#endif
-
 #endif /* __PMAC_H */
--- linux-2.5-plain/sound/ppc/powermac.c	2004-08-26 21:05:28.000000000 +0200
+++ linux-sound-plain/sound/ppc/powermac.c	2004-08-26 21:20:52.000000000 +0200
@@ -30,31 +30,19 @@
 #define CHIP_NAME "PMac"
 
 MODULE_DESCRIPTION("PowerMac");
-MODULE_CLASSES("{sound}");
-MODULE_DEVICES("{{Apple,PowerMac}}");
+MODULE_SUPPORTED_DEVICE("{{Apple,PowerMac}}");
 MODULE_LICENSE("GPL");
 
 static int index = SNDRV_DEFAULT_IDX1;		/* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;		/* ID for this card */
-/* static int enable = 1; */
-#ifdef PMAC_SUPPORT_PCM_BEEP
 static int enable_beep = 1;
-#endif
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for " CHIP_NAME " soundchip.");
-MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
 module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for " CHIP_NAME " soundchip.");
-MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
-/* module_param(enable, bool, 0444);
-   MODULE_PARM_DESC(enable, "Enable this soundchip.");
-   MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); */
-#ifdef PMAC_SUPPORT_PCM_BEEP
 module_param(enable_beep, bool, 0444);
 MODULE_PARM_DESC(enable_beep, "Enable beep using PCM.");
-MODULE_PARM_SYNTAX(enable_beep, SNDRV_ENABLED "," SNDRV_BOOLEAN_TRUE_DESC);
-#endif
 
 
 /*
@@ -133,10 +121,8 @@
 		goto __error;
 
 	chip->initialized = 1;
-#ifdef PMAC_SUPPORT_PCM_BEEP
 	if (enable_beep)
 		snd_pmac_attach_beep(chip);
-#endif
 
 	if ((err = snd_card_register(card)) < 0)
 		goto __error;
@@ -151,18 +137,14 @@
 
 
 /*
- * MODULE sutff
+ * MODULE stuff
  */
 
 static int __init alsa_card_pmac_init(void)
 {
 	int err;
-	if ((err = snd_pmac_probe()) < 0) {
-#ifdef MODULE
-		printk(KERN_ERR "no PMac soundchip found\n");
-#endif
+	if ((err = snd_pmac_probe()) < 0)
 		return err;
-	}
 	return 0;
 
 }
--- linux-2.5-plain/sound/ppc/awacs.c	2004-08-26 21:02:24.000000000 +0200
+++ linux-sound-plain/sound/ppc/awacs.c	2004-08-26 21:16:57.000000000 +0200
@@ -29,8 +29,6 @@
 #include <sound/core.h>
 #include "pmac.h"
 
-#define chip_t pmac_t
-
 
 #ifdef CONFIG_ADB_CUDA
 #define PMAC_AMP_AVAIL
@@ -574,11 +572,22 @@
 	AWACS_VOLUME("Master Playback Volume", 2, 6, 1),
 	AWACS_SWITCH("Master Capture Switch", 1, SHIFT_LOOPTHRU, 0),
 	AWACS_VOLUME("Capture Volume", 0, 4, 0),
-	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_LINE, 0),
 	AWACS_SWITCH("CD Capture Switch", 0, SHIFT_MUX_CD, 0),
+};
+
+/* FIXME: is this correct order?
+ * screamer (powerbook G3 pismo) seems to have different bits...
+ */
+static snd_kcontrol_new_t snd_pmac_awacs_mixers2[] __initdata = {
+	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_LINE, 0),
 	AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_MIC, 0),
 };
 
+static snd_kcontrol_new_t snd_pmac_screamer_mixers2[] __initdata = {
+	AWACS_SWITCH("Line Capture Switch", 0, SHIFT_MUX_MIC, 0),
+	AWACS_SWITCH("Mic Capture Switch", 0, SHIFT_MUX_LINE, 0),
+};
+
 static snd_kcontrol_new_t snd_pmac_awacs_master_sw __initdata =
 AWACS_SWITCH("Master Playback Switch", 1, SHIFT_HDMUTE, 1);
 
@@ -602,8 +611,6 @@
 AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1);
 
 
-#define num_controls(ary) (sizeof(ary) / sizeof(snd_kcontrol_new_t))
-
 /*
  * add new mixer elements to the card
  */
@@ -818,9 +825,17 @@
 	 */
 	strcpy(chip->card->mixername, "PowerMac AWACS");
 
-	if ((err = build_mixers(chip, num_controls(snd_pmac_awacs_mixers),
+	if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers),
 				snd_pmac_awacs_mixers)) < 0)
 		return err;
+	if (chip->model == PMAC_SCREAMER)
+		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mixers2),
+				   snd_pmac_screamer_mixers2);
+	else
+		err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mixers2),
+				   snd_pmac_awacs_mixers2);
+	if (err < 0)
+		return err;
 	chip->master_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_master_sw, chip);
 	if ((err = snd_ctl_add(chip->card, chip->master_sw_ctl)) < 0)
 		return err;
@@ -832,7 +847,7 @@
 		 * screamer registers.
 		 * in this case, it seems the route C is not used.
 		 */
-		if ((err = build_mixers(chip, num_controls(snd_pmac_awacs_amp_vol),
+		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_amp_vol),
 					snd_pmac_awacs_amp_vol)) < 0)
 			return err;
 		/* overwrite */
@@ -846,7 +861,7 @@
 #endif /* PMAC_AMP_AVAIL */
 	{
 		/* route A = headphone, route C = speaker */
-		if ((err = build_mixers(chip, num_controls(snd_pmac_awacs_speaker_vol),
+		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_speaker_vol),
 					snd_pmac_awacs_speaker_vol)) < 0)
 			return err;
 		chip->speaker_sw_ctl = snd_ctl_new1(&snd_pmac_awacs_speaker_sw, chip);
@@ -855,11 +870,11 @@
 	}
 
 	if (chip->model == PMAC_SCREAMER) {
-		if ((err = build_mixers(chip, num_controls(snd_pmac_screamer_mic_boost),
+		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_screamer_mic_boost),
 					snd_pmac_screamer_mic_boost)) < 0)
 			return err;
 	} else {
-		if ((err = build_mixers(chip, num_controls(snd_pmac_awacs_mic_boost),
+		if ((err = build_mixers(chip, ARRAY_SIZE(snd_pmac_awacs_mic_boost),
 					snd_pmac_awacs_mic_boost)) < 0)
 			return err;
 	}
--- linux-2.5-plain/sound/ppc/burgundy.c	2004-08-26 21:01:31.000000000 +0200
+++ linux-sound-plain/sound/ppc/burgundy.c	2004-08-26 21:15:31.000000000 +0200
@@ -28,8 +28,6 @@
 #include "pmac.h"
 #include "burgundy.h"
 
-#define chip_t pmac_t
-
 
 /* Waits for busy flag to clear */
 inline static void
@@ -324,8 +322,6 @@
 static snd_kcontrol_new_t snd_pmac_burgundy_speaker_sw __initdata = 
 BURGUNDY_OUTPUT_SWITCH("PC Speaker Playback Switch", 0, BURGUNDY_OUTPUT_INTERN, 0, 0);
 
-#define num_controls(ary) (sizeof(ary) / sizeof(snd_kcontrol_new_t))
-
 
 #ifdef PMAC_SUPPORT_AUTOMUTE
 /*
@@ -420,7 +416,7 @@
 	 */
 	strcpy(chip->card->mixername, "PowerMac Burgundy");
 
-	for (i = 0; i < num_controls(snd_pmac_burgundy_mixers); i++) {
+	for (i = 0; i < ARRAY_SIZE(snd_pmac_burgundy_mixers); i++) {
 		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_pmac_burgundy_mixers[i], chip))) < 0)
 			return err;
 	}
--- linux-2.5-plain/sound/ppc/daca.c	2004-08-26 21:01:02.000000000 +0200
+++ linux-sound-plain/sound/ppc/daca.c	2004-08-26 21:14:44.000000000 +0200
@@ -28,8 +28,6 @@
 #include <sound/core.h>
 #include "pmac.h"
 
-#define chip_t pmac_t
-
 /* i2c address */
 #define DACA_I2C_ADDR	0x4d
 
@@ -217,8 +215,6 @@
 	},
 };
 
-#define num_controls(ary) (sizeof(ary) / sizeof(snd_kcontrol_new_t))
-
 
 #ifdef CONFIG_PMAC_PBOOK
 static void daca_resume(pmac_t *chip)
@@ -272,7 +268,7 @@
 	 */
 	strcpy(chip->card->mixername, "PowerMac DACA");
 
-	for (i = 0; i < num_controls(daca_mixers); i++) {
+	for (i = 0; i < ARRAY_SIZE(daca_mixers); i++) {
 		if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&daca_mixers[i], chip))) < 0)
 			return err;
 	}
--- linux-2.5-plain/sound/ppc/tumbler.c	2004-08-26 21:00:41.000000000 +0200
+++ linux-sound-plain/sound/ppc/tumbler.c	2004-08-26 21:14:00.000000000 +0200
@@ -16,6 +16,11 @@
  *   You should have received a copy of the GNU General Public License
  *   along with this program; if not, write to the Free Software
  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ *
+ *   Rene Rebe <rene.rebe@gmx.net>:
+ *     * update from shadow registers on wakeup and headphone plug
+ *     * automatically toggle DRC on headphone plug
+ *	
  */
 
 
@@ -36,8 +41,6 @@
 #include "pmac.h"
 #include "tumbler_volume.h"
 
-#define chip_t pmac_t
-
 /* i2c address for tumbler */
 #define TAS_I2C_ADDR	0x34
 
@@ -759,12 +762,6 @@
 	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,
@@ -791,12 +788,6 @@
 	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,
@@ -826,6 +817,14 @@
 	.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
 /*
@@ -847,6 +846,29 @@
 	}
 }
 
+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) {
@@ -856,14 +878,25 @@
 			/* 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 */
@@ -872,7 +905,7 @@
 /* interrupt - headphone plug changed */
 static irqreturn_t headphone_intr(int irq, void *devid, struct pt_regs *regs)
 {
-	pmac_t *chip = snd_magic_cast(pmac_t, devid, return IRQ_NONE);
+	pmac_t *chip = devid;
 	if (chip->update_automute && chip->initialized) {
 		chip->update_automute(chip, 1);
 		return IRQ_HANDLED;
@@ -1114,11 +1147,17 @@
 	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: