summaryrefslogtreecommitdiffstats
path: root/sound/pcmcia
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-09-10 14:58:59 +0200
committerTakashi Iwai <tiwai@suse.de>2014-09-15 15:52:38 +0200
commit3b73cfe5598eda7f5540608acd63b86688242731 (patch)
tree2f405e7c5eefdf3c17e069905548237ceca2155b /sound/pcmcia
parent6336c20cdaee1dd13d01dfa8c07ce3b18bbc846f (diff)
downloadlinux-3b73cfe5598eda7f5540608acd63b86688242731.tar.bz2
ALSA: pdaudiocf: Use nonatomic PCM ops
Like other fixes, convert the tasklet to a threaded irq and replace spinlock with mutex appropriately. ak4117_lock remains as spinlock since it's called in another spinlock context from ak4117 driver. Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pcmcia')
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c13
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.h5
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_core.c8
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_irq.c23
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c5
5 files changed, 29 insertions, 25 deletions
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index 56bda124cd4a..07f4b33db3af 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -61,6 +61,7 @@ static void snd_pdacf_detach(struct pcmcia_device *p_dev);
static void pdacf_release(struct pcmcia_device *link)
{
+ free_irq(link->irq, link->priv);
pcmcia_disable_device(link);
}
@@ -220,11 +221,13 @@ static int pdacf_config(struct pcmcia_device *link)
ret = pcmcia_request_io(link);
if (ret)
- goto failed;
+ goto failed_preirq;
- ret = pcmcia_request_irq(link, pdacf_interrupt);
+ ret = request_threaded_irq(link->irq, pdacf_interrupt,
+ pdacf_threaded_irq,
+ IRQF_SHARED, link->devname, link->priv);
if (ret)
- goto failed;
+ goto failed_preirq;
ret = pcmcia_enable_device(link);
if (ret)
@@ -236,7 +239,9 @@ static int pdacf_config(struct pcmcia_device *link)
return 0;
-failed:
+ failed:
+ free_irq(link->irq, link->priv);
+failed_preirq:
pcmcia_disable_device(link);
return -ENODEV;
}
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.h b/sound/pcmcia/pdaudiocf/pdaudiocf.h
index ea41e57d7179..e9a7d3a784f7 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.h
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.h
@@ -88,10 +88,9 @@ struct snd_pdacf {
unsigned long port;
int irq;
- spinlock_t reg_lock;
+ struct mutex reg_lock;
unsigned short regmap[8];
unsigned short suspend_reg_scr;
- struct tasklet_struct tq;
spinlock_t ak4117_lock;
struct ak4117 *ak4117;
@@ -136,7 +135,7 @@ int snd_pdacf_resume(struct snd_pdacf *chip);
#endif
int snd_pdacf_pcm_new(struct snd_pdacf *chip);
irqreturn_t pdacf_interrupt(int irq, void *dev);
-void pdacf_tasklet(unsigned long private_data);
+irqreturn_t pdacf_threaded_irq(int irq, void *dev);
void pdacf_reinit(struct snd_pdacf *chip, int resume);
#endif /* __PDAUDIOCF_H */
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
index ea0adfb984ad..d724ab0653cf 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_core.c
@@ -162,9 +162,8 @@ struct snd_pdacf *snd_pdacf_create(struct snd_card *card)
if (chip == NULL)
return NULL;
chip->card = card;
- spin_lock_init(&chip->reg_lock);
+ mutex_init(&chip->reg_lock);
spin_lock_init(&chip->ak4117_lock);
- tasklet_init(&chip->tq, pdacf_tasklet, (unsigned long)chip);
card->private_data = chip;
pdacf_proc_init(chip);
@@ -174,19 +173,18 @@ struct snd_pdacf *snd_pdacf_create(struct snd_card *card)
static void snd_pdacf_ak4117_change(struct ak4117 *ak4117, unsigned char c0, unsigned char c1)
{
struct snd_pdacf *chip = ak4117->change_callback_private;
- unsigned long flags;
u16 val;
if (!(c0 & AK4117_UNLCK))
return;
- spin_lock_irqsave(&chip->reg_lock, flags);
+ mutex_lock(&chip->reg_lock);
val = chip->regmap[PDAUDIOCF_REG_SCR>>1];
if (ak4117->rcs0 & AK4117_UNLCK)
val |= PDAUDIOCF_BLUE_LED_OFF;
else
val &= ~PDAUDIOCF_BLUE_LED_OFF;
pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val);
- spin_unlock_irqrestore(&chip->reg_lock, flags);
+ mutex_unlock(&chip->reg_lock);
}
int snd_pdacf_ak4117_create(struct snd_pdacf *chip)
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
index dcd32201bc8c..ecf0fbd91794 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
@@ -30,6 +30,7 @@ irqreturn_t pdacf_interrupt(int irq, void *dev)
{
struct snd_pdacf *chip = dev;
unsigned short stat;
+ bool wake_thread = false;
if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
PDAUDIOCF_STAT_IS_CONFIGURED|
@@ -41,13 +42,13 @@ irqreturn_t pdacf_interrupt(int irq, void *dev)
if (stat & PDAUDIOCF_IRQOVR) /* should never happen */
snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
if (chip->pcm_substream)
- tasklet_schedule(&chip->tq);
+ wake_thread = true;
if (!(stat & PDAUDIOCF_IRQAKM))
stat |= PDAUDIOCF_IRQAKM; /* check rate */
}
if (get_irq_regs() != NULL)
snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
- return IRQ_HANDLED;
+ return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
}
static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
@@ -256,16 +257,16 @@ static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned i
}
}
-void pdacf_tasklet(unsigned long private_data)
+irqreturn_t pdacf_threaded_irq(int irq, void *dev)
{
- struct snd_pdacf *chip = (struct snd_pdacf *) private_data;
+ struct snd_pdacf *chip = dev;
int size, off, cont, rdp, wdp;
if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
- return;
+ return IRQ_HANDLED;
if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
- return;
+ return IRQ_HANDLED;
rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
@@ -311,15 +312,15 @@ void pdacf_tasklet(unsigned long private_data)
size -= cont;
}
#endif
- spin_lock(&chip->reg_lock);
+ mutex_lock(&chip->reg_lock);
while (chip->pcm_tdone >= chip->pcm_period) {
chip->pcm_hwptr += chip->pcm_period;
chip->pcm_hwptr %= chip->pcm_size;
chip->pcm_tdone -= chip->pcm_period;
- spin_unlock(&chip->reg_lock);
+ mutex_unlock(&chip->reg_lock);
snd_pcm_period_elapsed(chip->pcm_substream);
- spin_lock(&chip->reg_lock);
+ mutex_lock(&chip->reg_lock);
}
- spin_unlock(&chip->reg_lock);
- /* printk(KERN_DEBUG "TASKLET: end\n"); */
+ mutex_unlock(&chip->reg_lock);
+ return IRQ_HANDLED;
}
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
index 43f995a3f960..b48aa0a78c19 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c
@@ -77,7 +77,7 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
default:
return -EINVAL;
}
- spin_lock(&chip->reg_lock);
+ mutex_lock(&chip->reg_lock);
chip->pcm_running += inc;
tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR);
if (chip->pcm_running) {
@@ -91,7 +91,7 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
tmp |= val;
pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp);
__end:
- spin_unlock(&chip->reg_lock);
+ mutex_unlock(&chip->reg_lock);
snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE);
return ret;
}
@@ -296,6 +296,7 @@ int snd_pdacf_pcm_new(struct snd_pdacf *chip)
pcm->private_data = chip;
pcm->info_flags = 0;
+ pcm->nonatomic = true;
strcpy(pcm->name, chip->card->shortname);
chip->pcm = pcm;