Commit 634726b4 authored by Jaroslav Kysela's avatar Jaroslav Kysela

ALSA CVS update

D:2003/08/05 13:45:12
A:Takashi Iwai <tiwai@suse.de>
F:pci/es1968.c:1.46->1.47 
L:- fixed corruption of stream linked list in the interrupt handler.
L:- clean up the unnecessary atomic_t and spinlocks.
parent 1cea804d
...@@ -583,9 +583,8 @@ struct snd_es1968 { ...@@ -583,9 +583,8 @@ struct snd_es1968 {
/* Maestro Stuff */ /* Maestro Stuff */
u16 maestro_map[32]; u16 maestro_map[32];
atomic_t bobclient; /* active timer instancs */ int bobclient; /* active timer instancs */
int bob_freq; /* timer frequency */ int bob_freq; /* timer frequency */
spinlock_t bob_lock;
struct semaphore memory_mutex; /* memory lock */ struct semaphore memory_mutex; /* memory lock */
/* APU states */ /* APU states */
...@@ -884,13 +883,11 @@ static void snd_es1968_bob_start(es1968_t *chip) ...@@ -884,13 +883,11 @@ static void snd_es1968_bob_start(es1968_t *chip)
spin_unlock_irqrestore(&chip->reg_lock, flags); spin_unlock_irqrestore(&chip->reg_lock, flags);
} }
/* call with substream spinlock */
static void snd_es1968_bob_inc(es1968_t *chip, int freq) static void snd_es1968_bob_inc(es1968_t *chip, int freq)
{ {
unsigned long flags; chip->bobclient++;
if (chip->bobclient == 1) {
spin_lock_irqsave(&chip->bob_lock, flags);
atomic_inc(&chip->bobclient);
if (atomic_read(&chip->bobclient) == 1) {
chip->bob_freq = freq; chip->bob_freq = freq;
snd_es1968_bob_start(chip); snd_es1968_bob_start(chip);
} else if (chip->bob_freq < freq) { } else if (chip->bob_freq < freq) {
...@@ -898,35 +895,29 @@ static void snd_es1968_bob_inc(es1968_t *chip, int freq) ...@@ -898,35 +895,29 @@ static void snd_es1968_bob_inc(es1968_t *chip, int freq)
chip->bob_freq = freq; chip->bob_freq = freq;
snd_es1968_bob_start(chip); snd_es1968_bob_start(chip);
} }
spin_unlock_irqrestore(&chip->bob_lock, flags);
} }
/* call with substream spinlock */
static void snd_es1968_bob_dec(es1968_t *chip) static void snd_es1968_bob_dec(es1968_t *chip)
{ {
unsigned long flags; chip->bobclient--;
if (chip->bobclient <= 0)
spin_lock_irqsave(&chip->bob_lock, flags);
atomic_dec(&chip->bobclient);
if (atomic_read(&chip->bobclient) <= 0)
snd_es1968_bob_stop(chip); snd_es1968_bob_stop(chip);
else if (chip->bob_freq > ESM_BOB_FREQ) { else if (chip->bob_freq > ESM_BOB_FREQ) {
/* check reduction of timer frequency */ /* check reduction of timer frequency */
struct list_head *p; struct list_head *p;
int max_freq = ESM_BOB_FREQ; int max_freq = ESM_BOB_FREQ;
spin_lock(&chip->substream_lock);
list_for_each(p, &chip->substream_list) { list_for_each(p, &chip->substream_list) {
esschan_t *es = list_entry(p, esschan_t, list); esschan_t *es = list_entry(p, esschan_t, list);
if (max_freq < es->bob_freq) if (max_freq < es->bob_freq)
max_freq = es->bob_freq; max_freq = es->bob_freq;
} }
spin_unlock(&chip->substream_lock);
if (max_freq != chip->bob_freq) { if (max_freq != chip->bob_freq) {
snd_es1968_bob_stop(chip); snd_es1968_bob_stop(chip);
chip->bob_freq = max_freq; chip->bob_freq = max_freq;
snd_es1968_bob_start(chip); snd_es1968_bob_start(chip);
} }
} }
spin_unlock_irqrestore(&chip->bob_lock, flags);
} }
static int static int
...@@ -992,13 +983,7 @@ inline static void snd_es1968_trigger_apu(es1968_t *esm, int apu, int mode) ...@@ -992,13 +983,7 @@ inline static void snd_es1968_trigger_apu(es1968_t *esm, int apu, int mode)
static void snd_es1968_pcm_start(es1968_t *chip, esschan_t *es) static void snd_es1968_pcm_start(es1968_t *chip, esschan_t *es)
{ {
unsigned long flags; spin_lock(&chip->reg_lock);
spin_lock_irqsave(&chip->reg_lock, flags);
if (es->running) {
spin_unlock_irqrestore(&chip->reg_lock, flags);
return;
}
__apu_set_register(chip, es->apu[0], 5, es->base[0]); __apu_set_register(chip, es->apu[0], 5, es->base[0]);
snd_es1968_trigger_apu(chip, es->apu[0], es->apu_mode[0]); snd_es1968_trigger_apu(chip, es->apu[0], es->apu_mode[0]);
if (es->mode == ESM_MODE_CAPTURE) { if (es->mode == ESM_MODE_CAPTURE) {
...@@ -1013,27 +998,19 @@ static void snd_es1968_pcm_start(es1968_t *chip, esschan_t *es) ...@@ -1013,27 +998,19 @@ static void snd_es1968_pcm_start(es1968_t *chip, esschan_t *es)
snd_es1968_trigger_apu(chip, es->apu[3], es->apu_mode[3]); snd_es1968_trigger_apu(chip, es->apu[3], es->apu_mode[3]);
} }
} }
es->running = 1; spin_unlock(&chip->reg_lock);
spin_unlock_irqrestore(&chip->reg_lock, flags);
} }
static void snd_es1968_pcm_stop(es1968_t *chip, esschan_t *es) static void snd_es1968_pcm_stop(es1968_t *chip, esschan_t *es)
{ {
unsigned long flags; spin_lock(&chip->reg_lock);
spin_lock_irqsave(&chip->reg_lock, flags);
if (! es->running) {
spin_unlock_irqrestore(&chip->reg_lock, flags);
return;
}
snd_es1968_trigger_apu(chip, es->apu[0], 0); snd_es1968_trigger_apu(chip, es->apu[0], 0);
snd_es1968_trigger_apu(chip, es->apu[1], 0); snd_es1968_trigger_apu(chip, es->apu[1], 0);
if (es->mode == ESM_MODE_CAPTURE) { if (es->mode == ESM_MODE_CAPTURE) {
snd_es1968_trigger_apu(chip, es->apu[2], 0); snd_es1968_trigger_apu(chip, es->apu[2], 0);
snd_es1968_trigger_apu(chip, es->apu[3], 0); snd_es1968_trigger_apu(chip, es->apu[3], 0);
} }
es->running = 0; spin_unlock(&chip->reg_lock);
spin_unlock_irqrestore(&chip->reg_lock, flags);
} }
/* set the wavecache control reg */ /* set the wavecache control reg */
...@@ -1334,30 +1311,28 @@ static int snd_es1968_pcm_trigger(snd_pcm_substream_t *substream, int cmd) ...@@ -1334,30 +1311,28 @@ static int snd_es1968_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
esschan_t *es = snd_magic_cast(esschan_t, substream->runtime->private_data, return -ENXIO); esschan_t *es = snd_magic_cast(esschan_t, substream->runtime->private_data, return -ENXIO);
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&chip->substream_lock, flags);
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
if (es->running) if (es->running)
return 0; break;
snd_es1968_bob_inc(chip, es->bob_freq); snd_es1968_bob_inc(chip, es->bob_freq);
es->count = 0; es->count = 0;
es->hwptr = 0; es->hwptr = 0;
snd_es1968_pcm_start(chip, es); snd_es1968_pcm_start(chip, es);
spin_lock_irqsave(&chip->substream_lock, flags); es->running = 1;
list_add(&es->list, &chip->substream_list);
spin_unlock_irqrestore(&chip->substream_lock, flags);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
if (! es->running) if (! es->running)
return 0; break;
snd_es1968_pcm_stop(chip, es); snd_es1968_pcm_stop(chip, es);
spin_lock_irqsave(&chip->substream_lock, flags); es->running = 0;
list_del(&es->list);
spin_unlock_irqrestore(&chip->substream_lock, flags);
snd_es1968_bob_dec(chip); snd_es1968_bob_dec(chip);
break; break;
} }
spin_unlock_irqrestore(&chip->substream_lock, flags);
return 0; return 0;
} }
...@@ -1634,6 +1609,7 @@ static int snd_es1968_playback_open(snd_pcm_substream_t *substream) ...@@ -1634,6 +1609,7 @@ static int snd_es1968_playback_open(snd_pcm_substream_t *substream)
snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_runtime_t *runtime = substream->runtime;
esschan_t *es; esschan_t *es;
int apu1; int apu1;
unsigned long flags;
/* search 2 APUs */ /* search 2 APUs */
apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY); apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY);
...@@ -1653,13 +1629,16 @@ static int snd_es1968_playback_open(snd_pcm_substream_t *substream) ...@@ -1653,13 +1629,16 @@ static int snd_es1968_playback_open(snd_pcm_substream_t *substream)
es->running = 0; es->running = 0;
es->substream = substream; es->substream = substream;
es->mode = ESM_MODE_PLAY; es->mode = ESM_MODE_PLAY;
INIT_LIST_HEAD(&es->list);
runtime->private_data = es; runtime->private_data = es;
runtime->hw = snd_es1968_playback; runtime->hw = snd_es1968_playback;
runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max = runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max =
calc_available_memory_size(chip); calc_available_memory_size(chip);
spin_lock_irqsave(&chip->substream_lock, flags);
list_add(&es->list, &chip->substream_list);
spin_unlock_irqrestore(&chip->substream_lock, flags);
return 0; return 0;
} }
...@@ -1691,6 +1670,7 @@ static int snd_es1968_capture_open(snd_pcm_substream_t *substream) ...@@ -1691,6 +1670,7 @@ static int snd_es1968_capture_open(snd_pcm_substream_t *substream)
es1968_t *chip = snd_pcm_substream_chip(substream); es1968_t *chip = snd_pcm_substream_chip(substream);
esschan_t *es; esschan_t *es;
int apu1, apu2; int apu1, apu2;
unsigned long flags;
apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_CAPTURE); apu1 = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_CAPTURE);
if (apu1 < 0) if (apu1 < 0)
...@@ -1719,7 +1699,6 @@ static int snd_es1968_capture_open(snd_pcm_substream_t *substream) ...@@ -1719,7 +1699,6 @@ static int snd_es1968_capture_open(snd_pcm_substream_t *substream)
es->running = 0; es->running = 0;
es->substream = substream; es->substream = substream;
es->mode = ESM_MODE_CAPTURE; es->mode = ESM_MODE_CAPTURE;
INIT_LIST_HEAD(&es->list);
/* get mixbuffer */ /* get mixbuffer */
if ((es->mixbuf = snd_es1968_new_memory(chip, ESM_MIXBUF_SIZE)) == NULL) { if ((es->mixbuf = snd_es1968_new_memory(chip, ESM_MIXBUF_SIZE)) == NULL) {
...@@ -1734,6 +1713,10 @@ static int snd_es1968_capture_open(snd_pcm_substream_t *substream) ...@@ -1734,6 +1713,10 @@ static int snd_es1968_capture_open(snd_pcm_substream_t *substream)
runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max = runtime->hw.buffer_bytes_max = runtime->hw.period_bytes_max =
calc_available_memory_size(chip) - 1024; calc_available_memory_size(chip) - 1024;
spin_lock_irqsave(&chip->substream_lock, flags);
list_add(&es->list, &chip->substream_list);
spin_unlock_irqrestore(&chip->substream_lock, flags);
return 0; return 0;
} }
...@@ -1741,9 +1724,14 @@ static int snd_es1968_playback_close(snd_pcm_substream_t * substream) ...@@ -1741,9 +1724,14 @@ static int snd_es1968_playback_close(snd_pcm_substream_t * substream)
{ {
es1968_t *chip = snd_pcm_substream_chip(substream); es1968_t *chip = snd_pcm_substream_chip(substream);
esschan_t *es; esschan_t *es;
unsigned long flags;
if (substream->runtime->private_data == NULL) if (substream->runtime->private_data == NULL)
return 0; return 0;
es = snd_magic_cast(esschan_t, substream->runtime->private_data, return -ENXIO); es = snd_magic_cast(esschan_t, substream->runtime->private_data, return -ENXIO);
spin_lock_irqsave(&chip->substream_lock, flags);
list_del(&es->list);
spin_unlock_irqrestore(&chip->substream_lock, flags);
snd_es1968_free_apu_pair(chip, es->apu[0]); snd_es1968_free_apu_pair(chip, es->apu[0]);
snd_magic_kfree(es); snd_magic_kfree(es);
...@@ -1754,9 +1742,14 @@ static int snd_es1968_capture_close(snd_pcm_substream_t * substream) ...@@ -1754,9 +1742,14 @@ static int snd_es1968_capture_close(snd_pcm_substream_t * substream)
{ {
es1968_t *chip = snd_pcm_substream_chip(substream); es1968_t *chip = snd_pcm_substream_chip(substream);
esschan_t *es; esschan_t *es;
unsigned long flags;
if (substream->runtime->private_data == NULL) if (substream->runtime->private_data == NULL)
return 0; return 0;
es = snd_magic_cast(esschan_t, substream->runtime->private_data, return -ENXIO); es = snd_magic_cast(esschan_t, substream->runtime->private_data, return -ENXIO);
spin_lock_irqsave(&chip->substream_lock, flags);
list_del(&es->list);
spin_unlock_irqrestore(&chip->substream_lock, flags);
snd_es1968_free_memory(chip, es->mixbuf); snd_es1968_free_memory(chip, es->mixbuf);
snd_es1968_free_apu_pair(chip, es->apu[0]); snd_es1968_free_apu_pair(chip, es->apu[0]);
snd_es1968_free_apu_pair(chip, es->apu[2]); snd_es1968_free_apu_pair(chip, es->apu[2]);
...@@ -2035,14 +2028,12 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *r ...@@ -2035,14 +2028,12 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id, struct pt_regs *r
} }
if (event & ESM_SOUND_IRQ) { if (event & ESM_SOUND_IRQ) {
struct list_head *p, *n; struct list_head *p;
spin_lock(&chip->substream_lock); spin_lock(&chip->substream_lock);
/* we need to use list_for_each_safe here since the substream list_for_each(p, &chip->substream_list) {
* can be deleted in period_elapsed().
*/
list_for_each_safe(p, n, &chip->substream_list) {
esschan_t *es = list_entry(p, esschan_t, list); esschan_t *es = list_entry(p, esschan_t, list);
snd_es1968_update_pcm(chip, es); if (es->running)
snd_es1968_update_pcm(chip, es);
} }
spin_unlock(&chip->substream_lock); spin_unlock(&chip->substream_lock);
} }
...@@ -2467,7 +2458,7 @@ static void es1968_resume(es1968_t *chip) ...@@ -2467,7 +2458,7 @@ static void es1968_resume(es1968_t *chip)
snd_ac97_resume(chip->ac97); snd_ac97_resume(chip->ac97);
/* start timer again */ /* start timer again */
if (atomic_read(&chip->bobclient)) if (chip->bobclient)
snd_es1968_bob_start(chip); snd_es1968_bob_start(chip);
snd_power_change_state(card, SNDRV_CTL_POWER_D0); snd_power_change_state(card, SNDRV_CTL_POWER_D0);
...@@ -2613,8 +2604,6 @@ static int __devinit snd_es1968_create(snd_card_t * card, ...@@ -2613,8 +2604,6 @@ static int __devinit snd_es1968_create(snd_card_t * card,
for (i = 0; i < NR_APUS; i++) for (i = 0; i < NR_APUS; i++)
chip->apu[i] = ESM_APU_FREE; chip->apu[i] = ESM_APU_FREE;
atomic_set(&chip->bobclient, 0);
/* just to be sure */ /* just to be sure */
pci_set_master(pci); pci_set_master(pci);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment