[PATCH] ALSA AICA sound on SEGA Dreamcast - fix behaviour in poor resource conditions

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

 



Patch against code in alsa-kernel - tested with patched up 2.6.21-rc7
and working well

Submitted by: Adrian McMenamin <[email protected]>
Signed-off by: Adrian McMenamin <[email protected]>


diff -ruN aicaold/aica.c aicanew/aica.c
--- aicaold/aica.c	2007-07-05 23:01:39.000000000 +0100
+++ aicanew/aica.c	2007-07-05 23:02:02.000000000 +0100
@@ -65,10 +65,6 @@

/* Use workqueue */

-static struct spu_work_holder {
-	struct work_struct spu_dma_work;
-	void *sspointer;
-} spu_working;

static struct workqueue_struct *aica_queue;

@@ -252,18 +248,15 @@
static void run_spu_dma(struct work_struct *work)
{
	int buffer_size;
-	struct snd_pcm_substream *substream;
	struct snd_pcm_runtime *runtime;
	struct snd_card_aica *dreamcastcard;
-	struct spu_work_holder *holder = container_of(work, struct
spu_work_holder, spu_dma_work);
-	substream = holder-> sspointer;
-	dreamcastcard = substream->pcm->private_data;
-	runtime = substream->runtime;
+	dreamcastcard = container_of(work, struct snd_card_aica, spu_dma_work);
+	runtime = dreamcastcard->substream->runtime;
	if (unlikely(dreamcastcard->dma_check == 0)) {
		buffer_size = frames_to_bytes(runtime, runtime->buffer_size);
		if (runtime->channels > 1)
			dreamcastcard->channel->flags |= 0x01;
-		aica_dma_transfer(runtime->channels, buffer_size, substream);
+		aica_dma_transfer(runtime->channels, buffer_size, dreamcastcard->substream);
		startup_aica(dreamcastcard);
		dreamcastcard->clicks =
		    buffer_size / (AICA_PERIOD_SIZE * runtime->channels);
@@ -271,7 +264,7 @@
	} else {
		aica_dma_transfer(runtime->channels,
				  AICA_PERIOD_SIZE * runtime->channels,
-				  substream);
+				  dreamcastcard->substream);
		snd_pcm_period_elapsed(dreamcastcard->substream);
		dreamcastcard->clicks++;
		if (unlikely(dreamcastcard->clicks >= AICA_PERIOD_NUMBER))
@@ -307,7 +300,8 @@
		dreamcastcard->current_period = play_period;
	if (unlikely(dreamcastcard->dma_check == 0))
		dreamcastcard->dma_check = 1;
-		queue_work(aica_queue, &(spu_working.spu_dma_work));
+		queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
+
}

static void spu_begin_dma(struct snd_pcm_substream *substream)
@@ -317,10 +311,8 @@
	struct snd_pcm_runtime *runtime;
	runtime = substream->runtime;
	dreamcastcard = substream->pcm->private_data;
-	/*  Use queue to do the heavy lifting */
-	spu_working.sspointer = substream;
-	INIT_WORK(&(spu_working.spu_dma_work), run_spu_dma);
-	queue_work(aica_queue, &(spu_working.spu_dma_work));
+	//get the queue to do the work
+	queue_work(aica_queue, &(dreamcastcard->spu_dma_work));
	/* Timer may already be running */
	if (unlikely(dreamcastcard->timer.data)) {
		mod_timer(&dreamcastcard->timer, jiffies + 4);
@@ -366,7 +358,9 @@
				 *substream)
{
	struct snd_card_aica *dreamcastcard = substream->pcm->private_data;
+	flush_workqueue(aica_queue);
	del_timer(&dreamcastcard->timer);
+	aica_chn_halt();
	kfree(dreamcastcard->channel);
	spu_disable();
	return 0;
@@ -402,17 +396,10 @@
static int snd_aicapcm_pcm_trigger(struct snd_pcm_substream
				   *substream, int cmd)
{
-	struct snd_card_aica *dreamcastcard;
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
		spu_begin_dma(substream);
		break;
-	case SNDRV_PCM_TRIGGER_STOP:
-		dreamcastcard = substream->pcm->private_data;
-		if (dreamcastcard->timer.data)
-			del_timer(&dreamcastcard->timer);
-		aica_chn_halt();
-		break;
	default:
		return -EINVAL;
	}
@@ -610,6 +597,8 @@
	strcpy(dreamcastcard->card->shortname, SND_AICA_DRIVER);
	strcpy(dreamcastcard->card->longname,
	       "Yamaha AICA Super Intelligent Sound Processor for SEGA Dreamcast");
+	//start the worker thread
+	INIT_WORK(&(dreamcastcard->spu_dma_work), run_spu_dma);
	/* Load the PCM 'chip' */
	err = snd_aicapcmchip(dreamcastcard, 0);
	if (unlikely(err < 0))
diff -ruN aicaold/aica.h aicanew/aica.h
--- aicaold/aica.h	2007-07-05 23:01:39.000000000 +0100
+++ aicanew/aica.h	2007-07-05 23:02:02.000000000 +0100
@@ -69,6 +69,7 @@
};

struct snd_card_aica {
+	struct work_struct spu_dma_work;
	struct snd_card *card;
	struct aica_channel *channel;
	struct snd_pcm_substream *substream;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux