diff options
author | Takashi Iwai <tiwai@suse.de> | 2014-09-10 08:58:59 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-09-15 09:52:38 -0400 |
commit | 3b73cfe5598eda7f5540608acd63b86688242731 (patch) | |
tree | 2f405e7c5eefdf3c17e069905548237ceca2155b | |
parent | 6336c20cdaee1dd13d01dfa8c07ce3b18bbc846f (diff) |
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>
-rw-r--r-- | sound/pcmcia/pdaudiocf/pdaudiocf.c | 13 | ||||
-rw-r--r-- | sound/pcmcia/pdaudiocf/pdaudiocf.h | 5 | ||||
-rw-r--r-- | sound/pcmcia/pdaudiocf/pdaudiocf_core.c | 8 | ||||
-rw-r--r-- | sound/pcmcia/pdaudiocf/pdaudiocf_irq.c | 23 | ||||
-rw-r--r-- | sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | 5 |
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); | |||
61 | 61 | ||
62 | static void pdacf_release(struct pcmcia_device *link) | 62 | static void pdacf_release(struct pcmcia_device *link) |
63 | { | 63 | { |
64 | free_irq(link->irq, link->priv); | ||
64 | pcmcia_disable_device(link); | 65 | pcmcia_disable_device(link); |
65 | } | 66 | } |
66 | 67 | ||
@@ -220,11 +221,13 @@ static int pdacf_config(struct pcmcia_device *link) | |||
220 | 221 | ||
221 | ret = pcmcia_request_io(link); | 222 | ret = pcmcia_request_io(link); |
222 | if (ret) | 223 | if (ret) |
223 | goto failed; | 224 | goto failed_preirq; |
224 | 225 | ||
225 | ret = pcmcia_request_irq(link, pdacf_interrupt); | 226 | ret = request_threaded_irq(link->irq, pdacf_interrupt, |
227 | pdacf_threaded_irq, | ||
228 | IRQF_SHARED, link->devname, link->priv); | ||
226 | if (ret) | 229 | if (ret) |
227 | goto failed; | 230 | goto failed_preirq; |
228 | 231 | ||
229 | ret = pcmcia_enable_device(link); | 232 | ret = pcmcia_enable_device(link); |
230 | if (ret) | 233 | if (ret) |
@@ -236,7 +239,9 @@ static int pdacf_config(struct pcmcia_device *link) | |||
236 | 239 | ||
237 | return 0; | 240 | return 0; |
238 | 241 | ||
239 | failed: | 242 | failed: |
243 | free_irq(link->irq, link->priv); | ||
244 | failed_preirq: | ||
240 | pcmcia_disable_device(link); | 245 | pcmcia_disable_device(link); |
241 | return -ENODEV; | 246 | return -ENODEV; |
242 | } | 247 | } |
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 { | |||
88 | unsigned long port; | 88 | unsigned long port; |
89 | int irq; | 89 | int irq; |
90 | 90 | ||
91 | spinlock_t reg_lock; | 91 | struct mutex reg_lock; |
92 | unsigned short regmap[8]; | 92 | unsigned short regmap[8]; |
93 | unsigned short suspend_reg_scr; | 93 | unsigned short suspend_reg_scr; |
94 | struct tasklet_struct tq; | ||
95 | 94 | ||
96 | spinlock_t ak4117_lock; | 95 | spinlock_t ak4117_lock; |
97 | struct ak4117 *ak4117; | 96 | struct ak4117 *ak4117; |
@@ -136,7 +135,7 @@ int snd_pdacf_resume(struct snd_pdacf *chip); | |||
136 | #endif | 135 | #endif |
137 | int snd_pdacf_pcm_new(struct snd_pdacf *chip); | 136 | int snd_pdacf_pcm_new(struct snd_pdacf *chip); |
138 | irqreturn_t pdacf_interrupt(int irq, void *dev); | 137 | irqreturn_t pdacf_interrupt(int irq, void *dev); |
139 | void pdacf_tasklet(unsigned long private_data); | 138 | irqreturn_t pdacf_threaded_irq(int irq, void *dev); |
140 | void pdacf_reinit(struct snd_pdacf *chip, int resume); | 139 | void pdacf_reinit(struct snd_pdacf *chip, int resume); |
141 | 140 | ||
142 | #endif /* __PDAUDIOCF_H */ | 141 | #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) | |||
162 | if (chip == NULL) | 162 | if (chip == NULL) |
163 | return NULL; | 163 | return NULL; |
164 | chip->card = card; | 164 | chip->card = card; |
165 | spin_lock_init(&chip->reg_lock); | 165 | mutex_init(&chip->reg_lock); |
166 | spin_lock_init(&chip->ak4117_lock); | 166 | spin_lock_init(&chip->ak4117_lock); |
167 | tasklet_init(&chip->tq, pdacf_tasklet, (unsigned long)chip); | ||
168 | card->private_data = chip; | 167 | card->private_data = chip; |
169 | 168 | ||
170 | pdacf_proc_init(chip); | 169 | pdacf_proc_init(chip); |
@@ -174,19 +173,18 @@ struct snd_pdacf *snd_pdacf_create(struct snd_card *card) | |||
174 | static void snd_pdacf_ak4117_change(struct ak4117 *ak4117, unsigned char c0, unsigned char c1) | 173 | static void snd_pdacf_ak4117_change(struct ak4117 *ak4117, unsigned char c0, unsigned char c1) |
175 | { | 174 | { |
176 | struct snd_pdacf *chip = ak4117->change_callback_private; | 175 | struct snd_pdacf *chip = ak4117->change_callback_private; |
177 | unsigned long flags; | ||
178 | u16 val; | 176 | u16 val; |
179 | 177 | ||
180 | if (!(c0 & AK4117_UNLCK)) | 178 | if (!(c0 & AK4117_UNLCK)) |
181 | return; | 179 | return; |
182 | spin_lock_irqsave(&chip->reg_lock, flags); | 180 | mutex_lock(&chip->reg_lock); |
183 | val = chip->regmap[PDAUDIOCF_REG_SCR>>1]; | 181 | val = chip->regmap[PDAUDIOCF_REG_SCR>>1]; |
184 | if (ak4117->rcs0 & AK4117_UNLCK) | 182 | if (ak4117->rcs0 & AK4117_UNLCK) |
185 | val |= PDAUDIOCF_BLUE_LED_OFF; | 183 | val |= PDAUDIOCF_BLUE_LED_OFF; |
186 | else | 184 | else |
187 | val &= ~PDAUDIOCF_BLUE_LED_OFF; | 185 | val &= ~PDAUDIOCF_BLUE_LED_OFF; |
188 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); | 186 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, val); |
189 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 187 | mutex_unlock(&chip->reg_lock); |
190 | } | 188 | } |
191 | 189 | ||
192 | int snd_pdacf_ak4117_create(struct snd_pdacf *chip) | 190 | 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) | |||
30 | { | 30 | { |
31 | struct snd_pdacf *chip = dev; | 31 | struct snd_pdacf *chip = dev; |
32 | unsigned short stat; | 32 | unsigned short stat; |
33 | bool wake_thread = false; | ||
33 | 34 | ||
34 | if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE| | 35 | if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE| |
35 | PDAUDIOCF_STAT_IS_CONFIGURED| | 36 | PDAUDIOCF_STAT_IS_CONFIGURED| |
@@ -41,13 +42,13 @@ irqreturn_t pdacf_interrupt(int irq, void *dev) | |||
41 | if (stat & PDAUDIOCF_IRQOVR) /* should never happen */ | 42 | if (stat & PDAUDIOCF_IRQOVR) /* should never happen */ |
42 | snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n"); | 43 | snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n"); |
43 | if (chip->pcm_substream) | 44 | if (chip->pcm_substream) |
44 | tasklet_schedule(&chip->tq); | 45 | wake_thread = true; |
45 | if (!(stat & PDAUDIOCF_IRQAKM)) | 46 | if (!(stat & PDAUDIOCF_IRQAKM)) |
46 | stat |= PDAUDIOCF_IRQAKM; /* check rate */ | 47 | stat |= PDAUDIOCF_IRQAKM; /* check rate */ |
47 | } | 48 | } |
48 | if (get_irq_regs() != NULL) | 49 | if (get_irq_regs() != NULL) |
49 | snd_ak4117_check_rate_and_errors(chip->ak4117, 0); | 50 | snd_ak4117_check_rate_and_errors(chip->ak4117, 0); |
50 | return IRQ_HANDLED; | 51 | return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED; |
51 | } | 52 | } |
52 | 53 | ||
53 | static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port) | 54 | 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 | |||
256 | } | 257 | } |
257 | } | 258 | } |
258 | 259 | ||
259 | void pdacf_tasklet(unsigned long private_data) | 260 | irqreturn_t pdacf_threaded_irq(int irq, void *dev) |
260 | { | 261 | { |
261 | struct snd_pdacf *chip = (struct snd_pdacf *) private_data; | 262 | struct snd_pdacf *chip = dev; |
262 | int size, off, cont, rdp, wdp; | 263 | int size, off, cont, rdp, wdp; |
263 | 264 | ||
264 | if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED) | 265 | if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED) |
265 | return; | 266 | return IRQ_HANDLED; |
266 | 267 | ||
267 | if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream)) | 268 | if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream)) |
268 | return; | 269 | return IRQ_HANDLED; |
269 | 270 | ||
270 | rdp = inw(chip->port + PDAUDIOCF_REG_RDP); | 271 | rdp = inw(chip->port + PDAUDIOCF_REG_RDP); |
271 | wdp = inw(chip->port + PDAUDIOCF_REG_WDP); | 272 | wdp = inw(chip->port + PDAUDIOCF_REG_WDP); |
@@ -311,15 +312,15 @@ void pdacf_tasklet(unsigned long private_data) | |||
311 | size -= cont; | 312 | size -= cont; |
312 | } | 313 | } |
313 | #endif | 314 | #endif |
314 | spin_lock(&chip->reg_lock); | 315 | mutex_lock(&chip->reg_lock); |
315 | while (chip->pcm_tdone >= chip->pcm_period) { | 316 | while (chip->pcm_tdone >= chip->pcm_period) { |
316 | chip->pcm_hwptr += chip->pcm_period; | 317 | chip->pcm_hwptr += chip->pcm_period; |
317 | chip->pcm_hwptr %= chip->pcm_size; | 318 | chip->pcm_hwptr %= chip->pcm_size; |
318 | chip->pcm_tdone -= chip->pcm_period; | 319 | chip->pcm_tdone -= chip->pcm_period; |
319 | spin_unlock(&chip->reg_lock); | 320 | mutex_unlock(&chip->reg_lock); |
320 | snd_pcm_period_elapsed(chip->pcm_substream); | 321 | snd_pcm_period_elapsed(chip->pcm_substream); |
321 | spin_lock(&chip->reg_lock); | 322 | mutex_lock(&chip->reg_lock); |
322 | } | 323 | } |
323 | spin_unlock(&chip->reg_lock); | 324 | mutex_unlock(&chip->reg_lock); |
324 | /* printk(KERN_DEBUG "TASKLET: end\n"); */ | 325 | return IRQ_HANDLED; |
325 | } | 326 | } |
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) | |||
77 | default: | 77 | default: |
78 | return -EINVAL; | 78 | return -EINVAL; |
79 | } | 79 | } |
80 | spin_lock(&chip->reg_lock); | 80 | mutex_lock(&chip->reg_lock); |
81 | chip->pcm_running += inc; | 81 | chip->pcm_running += inc; |
82 | tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); | 82 | tmp = pdacf_reg_read(chip, PDAUDIOCF_REG_SCR); |
83 | if (chip->pcm_running) { | 83 | if (chip->pcm_running) { |
@@ -91,7 +91,7 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd) | |||
91 | tmp |= val; | 91 | tmp |= val; |
92 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp); | 92 | pdacf_reg_write(chip, PDAUDIOCF_REG_SCR, tmp); |
93 | __end: | 93 | __end: |
94 | spin_unlock(&chip->reg_lock); | 94 | mutex_unlock(&chip->reg_lock); |
95 | snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE); | 95 | snd_ak4117_check_rate_and_errors(chip->ak4117, AK4117_CHECK_NO_RATE); |
96 | return ret; | 96 | return ret; |
97 | } | 97 | } |
@@ -296,6 +296,7 @@ int snd_pdacf_pcm_new(struct snd_pdacf *chip) | |||
296 | 296 | ||
297 | pcm->private_data = chip; | 297 | pcm->private_data = chip; |
298 | pcm->info_flags = 0; | 298 | pcm->info_flags = 0; |
299 | pcm->nonatomic = true; | ||
299 | strcpy(pcm->name, chip->card->shortname); | 300 | strcpy(pcm->name, chip->card->shortname); |
300 | chip->pcm = pcm; | 301 | chip->pcm = pcm; |
301 | 302 | ||