| .. | .. |
|---|
| 23 | 23 | #define DMIX_WANTS_S16 1 |
|---|
| 24 | 24 | |
|---|
| 25 | 25 | /* |
|---|
| 26 | | - * Call snd_pcm_period_elapsed in a tasklet |
|---|
| 26 | + * Call snd_pcm_period_elapsed in a work |
|---|
| 27 | 27 | * This avoids spinlock messes and long-running irq contexts |
|---|
| 28 | 28 | */ |
|---|
| 29 | | -static void pcsp_call_pcm_elapsed(unsigned long priv) |
|---|
| 29 | +static void pcsp_call_pcm_elapsed(struct work_struct *work) |
|---|
| 30 | 30 | { |
|---|
| 31 | 31 | if (atomic_read(&pcsp_chip.timer_active)) { |
|---|
| 32 | 32 | struct snd_pcm_substream *substream; |
|---|
| .. | .. |
|---|
| 36 | 36 | } |
|---|
| 37 | 37 | } |
|---|
| 38 | 38 | |
|---|
| 39 | | -static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0); |
|---|
| 39 | +static DECLARE_WORK(pcsp_pcm_work, pcsp_call_pcm_elapsed); |
|---|
| 40 | 40 | |
|---|
| 41 | 41 | /* write the port and returns the next expire time in ns; |
|---|
| 42 | 42 | * called at the trigger-start and in hrtimer callback |
|---|
| .. | .. |
|---|
| 119 | 119 | if (periods_elapsed) { |
|---|
| 120 | 120 | chip->period_ptr += periods_elapsed * period_bytes; |
|---|
| 121 | 121 | chip->period_ptr %= buffer_bytes; |
|---|
| 122 | + queue_work(system_highpri_wq, &pcsp_pcm_work); |
|---|
| 122 | 123 | } |
|---|
| 123 | 124 | spin_unlock_irqrestore(&chip->substream_lock, flags); |
|---|
| 124 | | - |
|---|
| 125 | | - if (periods_elapsed) |
|---|
| 126 | | - tasklet_schedule(&pcsp_pcm_tasklet); |
|---|
| 127 | 125 | } |
|---|
| 128 | 126 | |
|---|
| 129 | 127 | enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle) |
|---|
| .. | .. |
|---|
| 196 | 194 | pcsp_stop_playing(chip); |
|---|
| 197 | 195 | local_irq_enable(); |
|---|
| 198 | 196 | hrtimer_cancel(&chip->timer); |
|---|
| 199 | | - tasklet_kill(&pcsp_pcm_tasklet); |
|---|
| 197 | + cancel_work_sync(&pcsp_pcm_work); |
|---|
| 200 | 198 | } |
|---|
| 201 | 199 | |
|---|
| 202 | 200 | static int snd_pcsp_playback_close(struct snd_pcm_substream *substream) |
|---|
| .. | .. |
|---|
| 214 | 212 | struct snd_pcm_hw_params *hw_params) |
|---|
| 215 | 213 | { |
|---|
| 216 | 214 | struct snd_pcsp *chip = snd_pcm_substream_chip(substream); |
|---|
| 217 | | - int err; |
|---|
| 218 | 215 | pcsp_sync_stop(chip); |
|---|
| 219 | | - err = snd_pcm_lib_malloc_pages(substream, |
|---|
| 220 | | - params_buffer_bytes(hw_params)); |
|---|
| 221 | | - if (err < 0) |
|---|
| 222 | | - return err; |
|---|
| 223 | 216 | return 0; |
|---|
| 224 | 217 | } |
|---|
| 225 | 218 | |
|---|
| .. | .. |
|---|
| 230 | 223 | printk(KERN_INFO "PCSP: hw_free called\n"); |
|---|
| 231 | 224 | #endif |
|---|
| 232 | 225 | pcsp_sync_stop(chip); |
|---|
| 233 | | - return snd_pcm_lib_free_pages(substream); |
|---|
| 226 | + return 0; |
|---|
| 234 | 227 | } |
|---|
| 235 | 228 | |
|---|
| 236 | 229 | static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream) |
|---|
| .. | .. |
|---|
| 327 | 320 | static const struct snd_pcm_ops snd_pcsp_playback_ops = { |
|---|
| 328 | 321 | .open = snd_pcsp_playback_open, |
|---|
| 329 | 322 | .close = snd_pcsp_playback_close, |
|---|
| 330 | | - .ioctl = snd_pcm_lib_ioctl, |
|---|
| 331 | 323 | .hw_params = snd_pcsp_playback_hw_params, |
|---|
| 332 | 324 | .hw_free = snd_pcsp_playback_hw_free, |
|---|
| 333 | 325 | .prepare = snd_pcsp_playback_prepare, |
|---|
| .. | .. |
|---|
| 350 | 342 | chip->pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; |
|---|
| 351 | 343 | strcpy(chip->pcm->name, "pcsp"); |
|---|
| 352 | 344 | |
|---|
| 353 | | - snd_pcm_lib_preallocate_pages_for_all(chip->pcm, |
|---|
| 354 | | - SNDRV_DMA_TYPE_CONTINUOUS, |
|---|
| 355 | | - snd_dma_continuous_data |
|---|
| 356 | | - (GFP_KERNEL), PCSP_BUFFER_SIZE, |
|---|
| 357 | | - PCSP_BUFFER_SIZE); |
|---|
| 345 | + snd_pcm_set_managed_buffer_all(chip->pcm, |
|---|
| 346 | + SNDRV_DMA_TYPE_CONTINUOUS, |
|---|
| 347 | + NULL, |
|---|
| 348 | + PCSP_BUFFER_SIZE, |
|---|
| 349 | + PCSP_BUFFER_SIZE); |
|---|
| 358 | 350 | |
|---|
| 359 | 351 | return 0; |
|---|
| 360 | 352 | } |
|---|