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

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



Package: kernel-source-2.6.8

Thanks Julien. I now forward this to the kernel-source-2.6.8 package in order
to not lose it in my mail archive.

Friendly,

Sven Luther

On Wed, Sep 08, 2004 at 11:44:56AM +0200, Julien BLACHE wrote:
> 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 
> 

Content-Description: Beep support for PowerMac
> --- 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;
>  
>  }

Content-Description: hardware support updates for awacs, daca, tumbler, burgundy
> --- 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: