ia64/linux-2.6.18-xen.hg

diff sound/mips/au1x00.c @ 0:831230e53067

Import 2.6.18 from kernel.org tarball.
author Ian Campbell <ian.campbell@xensource.com>
date Wed Apr 11 14:15:44 2007 +0100 (2007-04-11)
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/sound/mips/au1x00.c	Wed Apr 11 14:15:44 2007 +0100
     1.3 @@ -0,0 +1,693 @@
     1.4 +/*
     1.5 + * BRIEF MODULE DESCRIPTION
     1.6 + *  Driver for AMD Au1000 MIPS Processor, AC'97 Sound Port
     1.7 + *
     1.8 + * Copyright 2004 Cooper Street Innovations Inc.
     1.9 + * Author: Charles Eidsness	<charles@cooper-street.com>
    1.10 + *
    1.11 + *  This program is free software; you can redistribute  it and/or modify it
    1.12 + *  under  the terms of  the GNU General  Public License as published by the
    1.13 + *  Free Software Foundation;  either version 2 of the  License, or (at your
    1.14 + *  option) any later version.
    1.15 + *
    1.16 + *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
    1.17 + *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
    1.18 + *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
    1.19 + *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
    1.20 + *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
    1.21 + *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
    1.22 + *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
    1.23 + *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
    1.24 + *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    1.25 + *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.26 + *
    1.27 + *  You should have received a copy of the  GNU General Public License along
    1.28 + *  with this program; if not, write  to the Free Software Foundation, Inc.,
    1.29 + *  675 Mass Ave, Cambridge, MA 02139, USA.
    1.30 + *
    1.31 + * History:
    1.32 + *
    1.33 + * 2004-09-09 Charles Eidsness	-- Original verion -- based on
    1.34 + * 				  sa11xx-uda1341.c ALSA driver and the
    1.35 + *				  au1000.c OSS driver.
    1.36 + * 2004-09-09 Matt Porter	-- Added support for ALSA 1.0.6
    1.37 + *
    1.38 + */
    1.39 +
    1.40 +#include <linux/ioport.h>
    1.41 +#include <linux/interrupt.h>
    1.42 +#include <sound/driver.h>
    1.43 +#include <linux/init.h>
    1.44 +#include <linux/slab.h>
    1.45 +#include <linux/version.h>
    1.46 +#include <sound/core.h>
    1.47 +#include <sound/initval.h>
    1.48 +#include <sound/pcm.h>
    1.49 +#include <sound/pcm_params.h>
    1.50 +#include <sound/ac97_codec.h>
    1.51 +#include <asm/mach-au1x00/au1000.h>
    1.52 +#include <asm/mach-au1x00/au1000_dma.h>
    1.53 +
    1.54 +MODULE_AUTHOR("Charles Eidsness <charles@cooper-street.com>");
    1.55 +MODULE_DESCRIPTION("Au1000 AC'97 ALSA Driver");
    1.56 +MODULE_LICENSE("GPL");
    1.57 +MODULE_SUPPORTED_DEVICE("{{AMD,Au1000 AC'97}}");
    1.58 +
    1.59 +#define PLAYBACK 0
    1.60 +#define CAPTURE 1
    1.61 +#define AC97_SLOT_3 0x01
    1.62 +#define AC97_SLOT_4 0x02
    1.63 +#define AC97_SLOT_6 0x08
    1.64 +#define AC97_CMD_IRQ 31
    1.65 +#define READ 0
    1.66 +#define WRITE 1
    1.67 +#define READ_WAIT 2
    1.68 +#define RW_DONE 3
    1.69 +
    1.70 +struct au1000_period
    1.71 +{
    1.72 +	u32 start;
    1.73 +	u32 relative_end;	/*realtive to start of buffer*/
    1.74 +	struct au1000_period * next;
    1.75 +};
    1.76 +
    1.77 +/*Au1000 AC97 Port Control Reisters*/
    1.78 +struct au1000_ac97_reg {
    1.79 +	u32 volatile config;
    1.80 +	u32 volatile status;
    1.81 +	u32 volatile data;
    1.82 +	u32 volatile cmd;
    1.83 +	u32 volatile cntrl;
    1.84 +};
    1.85 +
    1.86 +struct audio_stream {
    1.87 +	struct snd_pcm_substream *substream;
    1.88 +	int dma;
    1.89 +	spinlock_t dma_lock;
    1.90 +	struct au1000_period * buffer;
    1.91 +	unsigned int period_size;
    1.92 +	unsigned int periods;
    1.93 +};
    1.94 +
    1.95 +struct snd_au1000 {
    1.96 +	struct snd_card *card;
    1.97 +	struct au1000_ac97_reg volatile *ac97_ioport;
    1.98 +
    1.99 +	struct resource *ac97_res_port;
   1.100 +	spinlock_t ac97_lock;
   1.101 +	struct snd_ac97 *ac97;
   1.102 +
   1.103 +	struct snd_pcm *pcm;
   1.104 +	struct audio_stream *stream[2];	/* playback & capture */
   1.105 +};
   1.106 +
   1.107 +/*--------------------------- Local Functions --------------------------------*/
   1.108 +static void
   1.109 +au1000_set_ac97_xmit_slots(struct snd_au1000 *au1000, long xmit_slots)
   1.110 +{
   1.111 +	u32 volatile ac97_config;
   1.112 +
   1.113 +	spin_lock(&au1000->ac97_lock);
   1.114 +	ac97_config = au1000->ac97_ioport->config;
   1.115 +	ac97_config = ac97_config & ~AC97C_XMIT_SLOTS_MASK;
   1.116 +	ac97_config |= (xmit_slots << AC97C_XMIT_SLOTS_BIT);
   1.117 +	au1000->ac97_ioport->config = ac97_config;
   1.118 +	spin_unlock(&au1000->ac97_lock);
   1.119 +}
   1.120 +
   1.121 +static void
   1.122 +au1000_set_ac97_recv_slots(struct snd_au1000 *au1000, long recv_slots)
   1.123 +{
   1.124 +	u32 volatile ac97_config;
   1.125 +
   1.126 +	spin_lock(&au1000->ac97_lock);
   1.127 +	ac97_config = au1000->ac97_ioport->config;
   1.128 +	ac97_config = ac97_config & ~AC97C_RECV_SLOTS_MASK;
   1.129 +	ac97_config |= (recv_slots << AC97C_RECV_SLOTS_BIT);
   1.130 +	au1000->ac97_ioport->config = ac97_config;
   1.131 +	spin_unlock(&au1000->ac97_lock);
   1.132 +}
   1.133 +
   1.134 +
   1.135 +static void
   1.136 +au1000_release_dma_link(struct audio_stream *stream)
   1.137 +{
   1.138 +	struct au1000_period * pointer;
   1.139 +	struct au1000_period * pointer_next;
   1.140 +
   1.141 +	stream->period_size = 0;
   1.142 +	stream->periods = 0;
   1.143 +	pointer = stream->buffer;
   1.144 +	if (! pointer)
   1.145 +		return;
   1.146 +	do {
   1.147 +		pointer_next = pointer->next;
   1.148 +		kfree(pointer);
   1.149 +		pointer = pointer_next;
   1.150 +	} while (pointer != stream->buffer);
   1.151 +	stream->buffer = NULL;
   1.152 +}
   1.153 +
   1.154 +static int
   1.155 +au1000_setup_dma_link(struct audio_stream *stream, unsigned int period_bytes,
   1.156 +		      unsigned int periods)
   1.157 +{
   1.158 +	struct snd_pcm_substream *substream = stream->substream;
   1.159 +	struct snd_pcm_runtime *runtime = substream->runtime;
   1.160 +	struct au1000_period *pointer;
   1.161 +	unsigned long dma_start;
   1.162 +	int i;
   1.163 +
   1.164 +	dma_start = virt_to_phys(runtime->dma_area);
   1.165 +
   1.166 +	if (stream->period_size == period_bytes &&
   1.167 +	    stream->periods == periods)
   1.168 +		return 0; /* not changed */
   1.169 +
   1.170 +	au1000_release_dma_link(stream);
   1.171 +
   1.172 +	stream->period_size = period_bytes;
   1.173 +	stream->periods = periods;
   1.174 +
   1.175 +	stream->buffer = kmalloc(sizeof(struct au1000_period), GFP_KERNEL);
   1.176 +	if (! stream->buffer)
   1.177 +		return -ENOMEM;
   1.178 +	pointer = stream->buffer;
   1.179 +	for (i = 0; i < periods; i++) {
   1.180 +		pointer->start = (u32)(dma_start + (i * period_bytes));
   1.181 +		pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1);
   1.182 +		if (i < periods - 1) {
   1.183 +			pointer->next = kmalloc(sizeof(struct au1000_period), GFP_KERNEL);
   1.184 +			if (! pointer->next) {
   1.185 +				au1000_release_dma_link(stream);
   1.186 +				return -ENOMEM;
   1.187 +			}
   1.188 +			pointer = pointer->next;
   1.189 +		}
   1.190 +	}
   1.191 +	pointer->next = stream->buffer;
   1.192 +	return 0;
   1.193 +}
   1.194 +
   1.195 +static void
   1.196 +au1000_dma_stop(struct audio_stream *stream)
   1.197 +{
   1.198 +	snd_assert(stream->buffer, return);
   1.199 +	disable_dma(stream->dma);
   1.200 +}
   1.201 +
   1.202 +static void
   1.203 +au1000_dma_start(struct audio_stream *stream)
   1.204 +{
   1.205 +	snd_assert(stream->buffer, return);
   1.206 +
   1.207 +	init_dma(stream->dma);
   1.208 +	if (get_dma_active_buffer(stream->dma) == 0) {
   1.209 +		clear_dma_done0(stream->dma);
   1.210 +		set_dma_addr0(stream->dma, stream->buffer->start);
   1.211 +		set_dma_count0(stream->dma, stream->period_size >> 1);
   1.212 +		set_dma_addr1(stream->dma, stream->buffer->next->start);
   1.213 +		set_dma_count1(stream->dma, stream->period_size >> 1);
   1.214 +	} else {
   1.215 +		clear_dma_done1(stream->dma);
   1.216 +		set_dma_addr1(stream->dma, stream->buffer->start);
   1.217 +		set_dma_count1(stream->dma, stream->period_size >> 1);
   1.218 +		set_dma_addr0(stream->dma, stream->buffer->next->start);
   1.219 +		set_dma_count0(stream->dma, stream->period_size >> 1);
   1.220 +	}
   1.221 +	enable_dma_buffers(stream->dma);
   1.222 +	start_dma(stream->dma);
   1.223 +}
   1.224 +
   1.225 +static irqreturn_t
   1.226 +au1000_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs)
   1.227 +{
   1.228 +	struct audio_stream *stream = (struct audio_stream *) dev_id;
   1.229 +	struct snd_pcm_substream *substream = stream->substream;
   1.230 +
   1.231 +	spin_lock(&stream->dma_lock);
   1.232 +	switch (get_dma_buffer_done(stream->dma)) {
   1.233 +	case DMA_D0:
   1.234 +		stream->buffer = stream->buffer->next;
   1.235 +		clear_dma_done0(stream->dma);
   1.236 +		set_dma_addr0(stream->dma, stream->buffer->next->start);
   1.237 +		set_dma_count0(stream->dma, stream->period_size >> 1);
   1.238 +		enable_dma_buffer0(stream->dma);
   1.239 +		break;
   1.240 +	case DMA_D1:
   1.241 +		stream->buffer = stream->buffer->next;
   1.242 +		clear_dma_done1(stream->dma);
   1.243 +		set_dma_addr1(stream->dma, stream->buffer->next->start);
   1.244 +		set_dma_count1(stream->dma, stream->period_size >> 1);
   1.245 +		enable_dma_buffer1(stream->dma);
   1.246 +		break;
   1.247 +	case (DMA_D0 | DMA_D1):
   1.248 +		printk(KERN_ERR "DMA %d missed interrupt.\n",stream->dma);
   1.249 +		au1000_dma_stop(stream);
   1.250 +		au1000_dma_start(stream);
   1.251 +		break;
   1.252 +	case (~DMA_D0 & ~DMA_D1):
   1.253 +		printk(KERN_ERR "DMA %d empty irq.\n",stream->dma);
   1.254 +	}
   1.255 +	spin_unlock(&stream->dma_lock);
   1.256 +	snd_pcm_period_elapsed(substream);
   1.257 +	return IRQ_HANDLED;
   1.258 +}
   1.259 +
   1.260 +/*-------------------------- PCM Audio Streams -------------------------------*/
   1.261 +
   1.262 +static unsigned int rates[] = {8000, 11025, 16000, 22050};
   1.263 +static struct snd_pcm_hw_constraint_list hw_constraints_rates = {
   1.264 +	.count	=  sizeof(rates) / sizeof(rates[0]),
   1.265 +	.list	= rates,
   1.266 +	.mask	= 0,
   1.267 +};
   1.268 +
   1.269 +static struct snd_pcm_hardware snd_au1000_hw =
   1.270 +{
   1.271 +	.info			= (SNDRV_PCM_INFO_INTERLEAVED | \
   1.272 +				SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID),
   1.273 +	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
   1.274 +	.rates			= (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |
   1.275 +				SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_22050),
   1.276 +	.rate_min		= 8000,
   1.277 +	.rate_max		= 22050,
   1.278 +	.channels_min		= 1,
   1.279 +	.channels_max		= 2,
   1.280 +	.buffer_bytes_max	= 128*1024,
   1.281 +	.period_bytes_min	= 32,
   1.282 +	.period_bytes_max	= 16*1024,
   1.283 +	.periods_min		= 8,
   1.284 +	.periods_max		= 255,
   1.285 +	.fifo_size		= 16,
   1.286 +};
   1.287 +
   1.288 +static int
   1.289 +snd_au1000_playback_open(struct snd_pcm_substream *substream)
   1.290 +{
   1.291 +	struct snd_au1000 *au1000 = substream->pcm->private_data;
   1.292 +
   1.293 +	au1000->stream[PLAYBACK]->substream = substream;
   1.294 +	au1000->stream[PLAYBACK]->buffer = NULL;
   1.295 +	substream->private_data = au1000->stream[PLAYBACK];
   1.296 +	substream->runtime->hw = snd_au1000_hw;
   1.297 +	return (snd_pcm_hw_constraint_list(substream->runtime, 0,
   1.298 +		SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0);
   1.299 +}
   1.300 +
   1.301 +static int
   1.302 +snd_au1000_capture_open(struct snd_pcm_substream *substream)
   1.303 +{
   1.304 +	struct snd_au1000 *au1000 = substream->pcm->private_data;
   1.305 +
   1.306 +	au1000->stream[CAPTURE]->substream = substream;
   1.307 +	au1000->stream[CAPTURE]->buffer = NULL;
   1.308 +	substream->private_data = au1000->stream[CAPTURE];
   1.309 +	substream->runtime->hw = snd_au1000_hw;
   1.310 +	return (snd_pcm_hw_constraint_list(substream->runtime, 0,
   1.311 +		SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0);
   1.312 +}
   1.313 +
   1.314 +static int
   1.315 +snd_au1000_playback_close(struct snd_pcm_substream *substream)
   1.316 +{
   1.317 +	struct snd_au1000 *au1000 = substream->pcm->private_data;
   1.318 +
   1.319 +	au1000->stream[PLAYBACK]->substream = NULL;
   1.320 +	return 0;
   1.321 +}
   1.322 +
   1.323 +static int
   1.324 +snd_au1000_capture_close(struct snd_pcm_substream *substream)
   1.325 +{
   1.326 +	struct snd_au1000 *au1000 = substream->pcm->private_data;
   1.327 +
   1.328 +	au1000->stream[CAPTURE]->substream = NULL;
   1.329 +	return 0;
   1.330 +}
   1.331 +
   1.332 +static int
   1.333 +snd_au1000_hw_params(struct snd_pcm_substream *substream,
   1.334 +					struct snd_pcm_hw_params *hw_params)
   1.335 +{
   1.336 +	struct audio_stream *stream = substream->private_data;
   1.337 +	int err;
   1.338 +
   1.339 +	err = snd_pcm_lib_malloc_pages(substream,
   1.340 +				       params_buffer_bytes(hw_params));
   1.341 +	if (err < 0)
   1.342 +		return err;
   1.343 +	return au1000_setup_dma_link(stream,
   1.344 +				     params_period_bytes(hw_params),
   1.345 +				     params_periods(hw_params));
   1.346 +}
   1.347 +
   1.348 +static int
   1.349 +snd_au1000_hw_free(struct snd_pcm_substream *substream)
   1.350 +{
   1.351 +	struct audio_stream *stream = substream->private_data;
   1.352 +	au1000_release_dma_link(stream);
   1.353 +	return snd_pcm_lib_free_pages(substream);
   1.354 +}
   1.355 +
   1.356 +static int
   1.357 +snd_au1000_playback_prepare(struct snd_pcm_substream *substream)
   1.358 +{
   1.359 +	struct snd_au1000 *au1000 = substream->pcm->private_data;
   1.360 +	struct snd_pcm_runtime *runtime = substream->runtime;
   1.361 +
   1.362 +	if (runtime->channels == 1)
   1.363 +		au1000_set_ac97_xmit_slots(au1000, AC97_SLOT_4);
   1.364 +	else
   1.365 +		au1000_set_ac97_xmit_slots(au1000, AC97_SLOT_3 | AC97_SLOT_4);
   1.366 +	snd_ac97_set_rate(au1000->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
   1.367 +	return 0;
   1.368 +}
   1.369 +
   1.370 +static int
   1.371 +snd_au1000_capture_prepare(struct snd_pcm_substream *substream)
   1.372 +{
   1.373 +	struct snd_au1000 *au1000 = substream->pcm->private_data;
   1.374 +	struct snd_pcm_runtime *runtime = substream->runtime;
   1.375 +
   1.376 +	if (runtime->channels == 1)
   1.377 +		au1000_set_ac97_recv_slots(au1000, AC97_SLOT_4);
   1.378 +	else
   1.379 +		au1000_set_ac97_recv_slots(au1000, AC97_SLOT_3 | AC97_SLOT_4);
   1.380 +	snd_ac97_set_rate(au1000->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
   1.381 +	return 0;
   1.382 +}
   1.383 +
   1.384 +static int
   1.385 +snd_au1000_trigger(struct snd_pcm_substream *substream, int cmd)
   1.386 +{
   1.387 +	struct audio_stream *stream = substream->private_data;
   1.388 +	int err = 0;
   1.389 +
   1.390 +	spin_lock(&stream->dma_lock);
   1.391 +	switch (cmd) {
   1.392 +	case SNDRV_PCM_TRIGGER_START:
   1.393 +		au1000_dma_start(stream);
   1.394 +		break;
   1.395 +	case SNDRV_PCM_TRIGGER_STOP:
   1.396 +		au1000_dma_stop(stream);
   1.397 +		break;
   1.398 +	default:
   1.399 +		err = -EINVAL;
   1.400 +		break;
   1.401 +	}
   1.402 +	spin_unlock(&stream->dma_lock);
   1.403 +	return err;
   1.404 +}
   1.405 +
   1.406 +static snd_pcm_uframes_t
   1.407 +snd_au1000_pointer(struct snd_pcm_substream *substream)
   1.408 +{
   1.409 +	struct audio_stream *stream = substream->private_data;
   1.410 +	struct snd_pcm_runtime *runtime = substream->runtime;
   1.411 +	long location;
   1.412 +
   1.413 +	spin_lock(&stream->dma_lock);
   1.414 +	location = get_dma_residue(stream->dma);
   1.415 +	spin_unlock(&stream->dma_lock);
   1.416 +	location = stream->buffer->relative_end - location;
   1.417 +	if (location == -1)
   1.418 +		location = 0;
   1.419 +	return bytes_to_frames(runtime,location);
   1.420 +}
   1.421 +
   1.422 +static struct snd_pcm_ops snd_card_au1000_playback_ops = {
   1.423 +	.open			= snd_au1000_playback_open,
   1.424 +	.close			= snd_au1000_playback_close,
   1.425 +	.ioctl			= snd_pcm_lib_ioctl,
   1.426 +	.hw_params	        = snd_au1000_hw_params,
   1.427 +	.hw_free	        = snd_au1000_hw_free,
   1.428 +	.prepare		= snd_au1000_playback_prepare,
   1.429 +	.trigger		= snd_au1000_trigger,
   1.430 +	.pointer		= snd_au1000_pointer,
   1.431 +};
   1.432 +
   1.433 +static struct snd_pcm_ops snd_card_au1000_capture_ops = {
   1.434 +	.open			= snd_au1000_capture_open,
   1.435 +	.close			= snd_au1000_capture_close,
   1.436 +	.ioctl			= snd_pcm_lib_ioctl,
   1.437 +	.hw_params	        = snd_au1000_hw_params,
   1.438 +	.hw_free	        = snd_au1000_hw_free,
   1.439 +	.prepare		= snd_au1000_capture_prepare,
   1.440 +	.trigger		= snd_au1000_trigger,
   1.441 +	.pointer		= snd_au1000_pointer,
   1.442 +};
   1.443 +
   1.444 +static int __devinit
   1.445 +snd_au1000_pcm_new(struct snd_au1000 *au1000)
   1.446 +{
   1.447 +	struct snd_pcm *pcm;
   1.448 +	int err;
   1.449 +	unsigned long flags;
   1.450 +
   1.451 +	if ((err = snd_pcm_new(au1000->card, "AU1000 AC97 PCM", 0, 1, 1, &pcm)) < 0)
   1.452 +		return err;
   1.453 +
   1.454 +	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
   1.455 +		snd_dma_continuous_data(GFP_KERNEL), 128*1024, 128*1024);
   1.456 +
   1.457 +	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
   1.458 +		&snd_card_au1000_playback_ops);
   1.459 +	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
   1.460 +		&snd_card_au1000_capture_ops);
   1.461 +
   1.462 +	pcm->private_data = au1000;
   1.463 +	pcm->info_flags = 0;
   1.464 +	strcpy(pcm->name, "Au1000 AC97 PCM");
   1.465 +
   1.466 +	spin_lock_init(&au1000->stream[PLAYBACK]->dma_lock);
   1.467 +	spin_lock_init(&au1000->stream[CAPTURE]->dma_lock);
   1.468 +
   1.469 +	flags = claim_dma_lock();
   1.470 +	if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX,
   1.471 +			"AC97 TX", au1000_dma_interrupt, IRQF_DISABLED,
   1.472 +			au1000->stream[PLAYBACK])) < 0) {
   1.473 +		release_dma_lock(flags);
   1.474 +		return -EBUSY;
   1.475 +	}
   1.476 +	if ((au1000->stream[CAPTURE]->dma = request_au1000_dma(DMA_ID_AC97C_RX,
   1.477 +			"AC97 RX", au1000_dma_interrupt, IRQF_DISABLED,
   1.478 +			au1000->stream[CAPTURE])) < 0){
   1.479 +		release_dma_lock(flags);
   1.480 +		return -EBUSY;
   1.481 +	}
   1.482 +	/* enable DMA coherency in read/write DMA channels */
   1.483 +	set_dma_mode(au1000->stream[PLAYBACK]->dma,
   1.484 +		     get_dma_mode(au1000->stream[PLAYBACK]->dma) & ~DMA_NC);
   1.485 +	set_dma_mode(au1000->stream[CAPTURE]->dma,
   1.486 +		     get_dma_mode(au1000->stream[CAPTURE]->dma) & ~DMA_NC);
   1.487 +	release_dma_lock(flags);
   1.488 +	au1000->pcm = pcm;
   1.489 +	return 0;
   1.490 +}
   1.491 +
   1.492 +
   1.493 +/*-------------------------- AC97 CODEC Control ------------------------------*/
   1.494 +
   1.495 +static unsigned short
   1.496 +snd_au1000_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
   1.497 +{
   1.498 +	struct snd_au1000 *au1000 = ac97->private_data;
   1.499 +	u32 volatile cmd;
   1.500 +	u16 volatile data;
   1.501 +	int             i;
   1.502 +
   1.503 +	spin_lock(&au1000->ac97_lock);
   1.504 +/* would rather use the interupt than this polling but it works and I can't
   1.505 +get the interupt driven case to work efficiently */
   1.506 +	for (i = 0; i < 0x5000; i++)
   1.507 +		if (!(au1000->ac97_ioport->status & AC97C_CP))
   1.508 +			break;
   1.509 +	if (i == 0x5000)
   1.510 +		printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n");
   1.511 +
   1.512 +	cmd = (u32) reg & AC97C_INDEX_MASK;
   1.513 +	cmd |= AC97C_READ;
   1.514 +	au1000->ac97_ioport->cmd = cmd;
   1.515 +
   1.516 +	/* now wait for the data */
   1.517 +	for (i = 0; i < 0x5000; i++)
   1.518 +		if (!(au1000->ac97_ioport->status & AC97C_CP))
   1.519 +			break;
   1.520 +	if (i == 0x5000) {
   1.521 +		printk(KERN_ERR "au1000 AC97: AC97 command read timeout\n");
   1.522 +		return 0;
   1.523 +	}
   1.524 +
   1.525 +	data = au1000->ac97_ioport->cmd & 0xffff;
   1.526 +	spin_unlock(&au1000->ac97_lock);
   1.527 +
   1.528 +	return data;
   1.529 +
   1.530 +}
   1.531 +
   1.532 +
   1.533 +static void
   1.534 +snd_au1000_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
   1.535 +{
   1.536 +	struct snd_au1000 *au1000 = ac97->private_data;
   1.537 +	u32 cmd;
   1.538 +	int i;
   1.539 +
   1.540 +	spin_lock(&au1000->ac97_lock);
   1.541 +/* would rather use the interupt than this polling but it works and I can't
   1.542 +get the interupt driven case to work efficiently */
   1.543 +	for (i = 0; i < 0x5000; i++)
   1.544 +		if (!(au1000->ac97_ioport->status & AC97C_CP))
   1.545 +			break;
   1.546 +	if (i == 0x5000)
   1.547 +		printk(KERN_ERR "au1000 AC97: AC97 command write timeout\n");
   1.548 +
   1.549 +	cmd = (u32) reg & AC97C_INDEX_MASK;
   1.550 +	cmd &= ~AC97C_READ;
   1.551 +	cmd |= ((u32) val << AC97C_WD_BIT);
   1.552 +	au1000->ac97_ioport->cmd = cmd;
   1.553 +	spin_unlock(&au1000->ac97_lock);
   1.554 +}
   1.555 +
   1.556 +static int __devinit
   1.557 +snd_au1000_ac97_new(struct snd_au1000 *au1000)
   1.558 +{
   1.559 +	int err;
   1.560 +	struct snd_ac97_bus *pbus;
   1.561 +	struct snd_ac97_template ac97;
   1.562 + 	static struct snd_ac97_bus_ops ops = {
   1.563 +		.write = snd_au1000_ac97_write,
   1.564 +		.read = snd_au1000_ac97_read,
   1.565 +	};
   1.566 +
   1.567 +	if ((au1000->ac97_res_port = request_mem_region(CPHYSADDR(AC97C_CONFIG),
   1.568 +	       		0x100000, "Au1x00 AC97")) == NULL) {
   1.569 +		snd_printk(KERN_ERR "ALSA AC97: can't grap AC97 port\n");
   1.570 +		return -EBUSY;
   1.571 +	}
   1.572 +	au1000->ac97_ioport = (struct au1000_ac97_reg *)
   1.573 +		KSEG1ADDR(au1000->ac97_res_port->start);
   1.574 +
   1.575 +	spin_lock_init(&au1000->ac97_lock);
   1.576 +
   1.577 +	/* configure pins for AC'97
   1.578 +	TODO: move to board_setup.c */
   1.579 +	au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC);
   1.580 +
   1.581 +	/* Initialise Au1000's AC'97 Control Block */
   1.582 +	au1000->ac97_ioport->cntrl = AC97C_RS | AC97C_CE;
   1.583 +	udelay(10);
   1.584 +	au1000->ac97_ioport->cntrl = AC97C_CE;
   1.585 +	udelay(10);
   1.586 +
   1.587 +	/* Initialise External CODEC -- cold reset */
   1.588 +	au1000->ac97_ioport->config = AC97C_RESET;
   1.589 +	udelay(10);
   1.590 +	au1000->ac97_ioport->config = 0x0;
   1.591 +	mdelay(5);
   1.592 +
   1.593 +	/* Initialise AC97 middle-layer */
   1.594 +	if ((err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus)) < 0)
   1.595 + 		return err;
   1.596 +
   1.597 +	memset(&ac97, 0, sizeof(ac97));
   1.598 +	ac97.private_data = au1000;
   1.599 +	if ((err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97)) < 0)
   1.600 +		return err;
   1.601 +
   1.602 +	return 0;
   1.603 +}
   1.604 +
   1.605 +/*------------------------------ Setup / Destroy ----------------------------*/
   1.606 +
   1.607 +void
   1.608 +snd_au1000_free(struct snd_card *card)
   1.609 +{
   1.610 +	struct snd_au1000 *au1000 = card->private_data;
   1.611 +
   1.612 +	if (au1000->ac97_res_port) {
   1.613 +		/* put internal AC97 block into reset */
   1.614 +		au1000->ac97_ioport->cntrl = AC97C_RS;
   1.615 +		au1000->ac97_ioport = NULL;
   1.616 +		release_and_free_resource(au1000->ac97_res_port);
   1.617 +	}
   1.618 +
   1.619 +	if (au1000->stream[PLAYBACK]) {
   1.620 +	  	if (au1000->stream[PLAYBACK]->dma >= 0)
   1.621 +			free_au1000_dma(au1000->stream[PLAYBACK]->dma);
   1.622 +		kfree(au1000->stream[PLAYBACK]);
   1.623 +	}
   1.624 +
   1.625 +	if (au1000->stream[CAPTURE]) {
   1.626 +		if (au1000->stream[CAPTURE]->dma >= 0)
   1.627 +			free_au1000_dma(au1000->stream[CAPTURE]->dma);
   1.628 +		kfree(au1000->stream[CAPTURE]);
   1.629 +	}
   1.630 +}
   1.631 +
   1.632 +
   1.633 +static struct snd_card *au1000_card;
   1.634 +
   1.635 +static int __init
   1.636 +au1000_init(void)
   1.637 +{
   1.638 +	int err;
   1.639 +	struct snd_card *card;
   1.640 +	struct snd_au1000 *au1000;
   1.641 +
   1.642 +	card = snd_card_new(-1, "AC97", THIS_MODULE, sizeof(struct snd_au1000));
   1.643 +	if (card == NULL)
   1.644 +		return -ENOMEM;
   1.645 +
   1.646 +	card->private_free = snd_au1000_free;
   1.647 +	au1000 = card->private_data;
   1.648 +	au1000->card = card;
   1.649 +
   1.650 +	au1000->stream[PLAYBACK] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL);
   1.651 +	au1000->stream[CAPTURE ] = kmalloc(sizeof(struct audio_stream), GFP_KERNEL);
   1.652 +	/* so that snd_au1000_free will work as intended */
   1.653 + 	au1000->ac97_res_port = NULL;
   1.654 +	if (au1000->stream[PLAYBACK])
   1.655 +		au1000->stream[PLAYBACK]->dma = -1;
   1.656 +	if (au1000->stream[CAPTURE ])
   1.657 +		au1000->stream[CAPTURE ]->dma = -1;
   1.658 +
   1.659 +	if (au1000->stream[PLAYBACK] == NULL ||
   1.660 +	    au1000->stream[CAPTURE ] == NULL) {
   1.661 +		snd_card_free(card);
   1.662 +		return -ENOMEM;
   1.663 +	}
   1.664 +
   1.665 +	if ((err = snd_au1000_ac97_new(au1000)) < 0 ) {
   1.666 +		snd_card_free(card);
   1.667 +		return err;
   1.668 +	}
   1.669 +
   1.670 +	if ((err = snd_au1000_pcm_new(au1000)) < 0) {
   1.671 +		snd_card_free(card);
   1.672 +		return err;
   1.673 +	}
   1.674 +
   1.675 +	strcpy(card->driver, "Au1000-AC97");
   1.676 +	strcpy(card->shortname, "AMD Au1000-AC97");
   1.677 +	sprintf(card->longname, "AMD Au1000--AC97 ALSA Driver");
   1.678 +
   1.679 +	if ((err = snd_card_register(card)) < 0) {
   1.680 +		snd_card_free(card);
   1.681 +		return err;
   1.682 +	}
   1.683 +
   1.684 +	printk( KERN_INFO "ALSA AC97: Driver Initialized\n" );
   1.685 +	au1000_card = card;
   1.686 +	return 0;
   1.687 +}
   1.688 +
   1.689 +static void __exit au1000_exit(void)
   1.690 +{
   1.691 +	snd_card_free(au1000_card);
   1.692 +}
   1.693 +
   1.694 +module_init(au1000_init);
   1.695 +module_exit(au1000_exit);
   1.696 +