return 0;
 }
 
-static void pcxhr_trigger_tasklet(unsigned long arg)
+static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
 {
-       unsigned long flags;
        int i, j, err;
        struct pcxhr_pipe *pipe;
        struct snd_pcxhr *chip;
-       struct pcxhr_mgr *mgr = (struct pcxhr_mgr*)(arg);
        int capture_mask = 0;
        int playback_mask = 0;
 
        }
        if (capture_mask == 0 && playback_mask == 0) {
                mutex_unlock(&mgr->setup_mutex);
-               dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : no pipes\n");
+               dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : no pipes\n");
                return;
        }
 
-       dev_dbg(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
+       dev_dbg(&mgr->pci->dev, "pcxhr_start_linked_stream : "
                    "playback_mask=%x capture_mask=%x\n",
                    playback_mask, capture_mask);
 
        err = pcxhr_set_pipe_state(mgr,  playback_mask, capture_mask, 0);
        if (err) {
                mutex_unlock(&mgr->setup_mutex);
-               dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
+               dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : "
                           "error stop pipes (P%x C%x)\n",
                           playback_mask, capture_mask);
                return;
        err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1);
        if (err) {
                mutex_unlock(&mgr->setup_mutex);
-               dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : "
+               dev_err(&mgr->pci->dev, "pcxhr_start_linked_stream : "
                           "error start pipes (P%x C%x)\n",
                           playback_mask, capture_mask);
                return;
        /* put the streams into the running state now
         * (increment pointer by interrupt)
         */
-       spin_lock_irqsave(&mgr->lock, flags);
+       mutex_lock(&mgr->lock);
        for ( i =0; i < mgr->num_cards; i++) {
                struct pcxhr_stream *stream;
                chip = mgr->chip[i];
                        }
                }
        }
-       spin_unlock_irqrestore(&mgr->lock, flags);
+       mutex_unlock(&mgr->lock);
 
        mutex_unlock(&mgr->setup_mutex);
 
 #ifdef CONFIG_SND_DEBUG_VERBOSE
        do_gettimeofday(&my_tv2);
-       dev_dbg(&mgr->pci->dev, "***TRIGGER TASKLET*** TIME = %ld (err = %x)\n",
+       dev_dbg(&mgr->pci->dev, "***TRIGGER START*** TIME = %ld (err = %x)\n",
                    (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
 #endif
 }
                                        PCXHR_STREAM_STATUS_SCHEDULE_RUN;
                                snd_pcm_trigger_done(s, subs);
                        }
-                       tasklet_schedule(&chip->mgr->trigger_taskq);
+                       pcxhr_start_linked_stream(chip->mgr);
                } else {
                        stream = subs->runtime->private_data;
                        snd_printdd("Only one Substream %c %d\n",
 
 static snd_pcm_uframes_t pcxhr_stream_pointer(struct snd_pcm_substream *subs)
 {
-       unsigned long flags;
        u_int32_t timer_period_frag;
        int timer_buf_periods;
        struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);
        struct snd_pcm_runtime *runtime = subs->runtime;
        struct pcxhr_stream *stream  = runtime->private_data;
 
-       spin_lock_irqsave(&chip->mgr->lock, flags);
+       mutex_lock(&chip->mgr->lock);
 
        /* get the period fragment and the nb of periods in the buffer */
        timer_period_frag = stream->timer_period_frag;
        timer_buf_periods = stream->timer_buf_periods;
 
-       spin_unlock_irqrestore(&chip->mgr->lock, flags);
+       mutex_unlock(&chip->mgr->lock);
 
        return (snd_pcm_uframes_t)((timer_buf_periods * runtime->period_size) +
                                   timer_period_frag);
                snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcxhr_ops);
 
        pcm->info_flags = 0;
+       pcm->nonatomic = true;
        strcpy(pcm->name, name);
 
        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
        mgr->pci = pci;
        mgr->irq = -1;
 
-       if (request_irq(pci->irq, pcxhr_interrupt, IRQF_SHARED,
-                       KBUILD_MODNAME, mgr)) {
+       if (request_threaded_irq(pci->irq, pcxhr_interrupt,
+                                pcxhr_threaded_irq, IRQF_SHARED,
+                                KBUILD_MODNAME, mgr)) {
                dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq);
                pcxhr_free(mgr);
                return -EBUSY;
                mgr->shortname,
                mgr->port[0], mgr->port[1], mgr->port[2], mgr->irq);
 
-       /* ISR spinlock  */
-       spin_lock_init(&mgr->lock);
-       spin_lock_init(&mgr->msg_lock);
+       /* ISR lock  */
+       mutex_init(&mgr->lock);
+       mutex_init(&mgr->msg_lock);
 
        /* init setup mutex*/
        mutex_init(&mgr->setup_mutex);
 
-       /* init taslket */
-       tasklet_init(&mgr->msg_taskq, pcxhr_msg_tasklet,
-                    (unsigned long) mgr);
-       tasklet_init(&mgr->trigger_taskq, pcxhr_trigger_tasklet,
-                    (unsigned long) mgr);
-
        mgr->prmh = kmalloc(sizeof(*mgr->prmh) + 
                            sizeof(u32) * (PCXHR_SIZE_MAX_LONG_STATUS -
                                           PCXHR_SIZE_MAX_STATUS),
 
        char shortname[32];             /* short name of this soundcard */
        char longname[96];              /* name of this soundcard */
 
-       /* message tasklet */
-       struct tasklet_struct msg_taskq;
        struct pcxhr_rmh *prmh;
-       /* trigger tasklet */
-       struct tasklet_struct trigger_taskq;
 
-       spinlock_t lock;                /* interrupt spinlock */
-       spinlock_t msg_lock;            /* message spinlock */
+       struct mutex lock;              /* interrupt lock */
+       struct mutex msg_lock;          /* message lock */
 
        struct mutex setup_mutex;       /* mutex used in hw_params, open and close */
        struct mutex mixer_mutex;       /* mutex for mixer */
 
  */
 int pcxhr_send_msg(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh)
 {
-       unsigned long flags;
        int err;
-       spin_lock_irqsave(&mgr->msg_lock, flags);
+
+       mutex_lock(&mgr->msg_lock);
        err = pcxhr_send_msg_nolock(mgr, rmh);
-       spin_unlock_irqrestore(&mgr->msg_lock, flags);
+       mutex_unlock(&mgr->msg_lock);
        return err;
 }
 
                                unsigned int value, int *changed)
 {
        struct pcxhr_rmh rmh;
-       unsigned long flags;
        int err;
 
-       spin_lock_irqsave(&mgr->msg_lock, flags);
+       mutex_lock(&mgr->msg_lock);
        if ((mgr->io_num_reg_cont & mask) == value) {
                dev_dbg(&mgr->pci->dev,
                        "IO_NUM_REG_CONT mask %x already is set to %x\n",
                            mask, value);
                if (changed)
                        *changed = 0;
-               spin_unlock_irqrestore(&mgr->msg_lock, flags);
+               mutex_unlock(&mgr->msg_lock);
                return 0;       /* already programmed */
        }
        pcxhr_init_rmh(&rmh, CMD_ACCESS_IO_WRITE);
                if (changed)
                        *changed = 1;
        }
-       spin_unlock_irqrestore(&mgr->msg_lock, flags);
+       mutex_unlock(&mgr->msg_lock);
        return err;
 }
 
 }
 
 
-void pcxhr_msg_tasklet(unsigned long arg)
+static void pcxhr_msg_thread(struct pcxhr_mgr *mgr)
 {
-       struct pcxhr_mgr *mgr = (struct pcxhr_mgr *)(arg);
        struct pcxhr_rmh *prmh = mgr->prmh;
        int err;
        int i, j;
 
        if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE)
                dev_dbg(&mgr->pci->dev,
-                       "TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n");
+                       "PCXHR_IRQ_FREQ_CHANGE event occurred\n");
        if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE)
                dev_dbg(&mgr->pci->dev,
-                       "TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n");
+                       "PCXHR_IRQ_TIME_CODE event occurred\n");
        if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY)
                dev_dbg(&mgr->pci->dev,
-                       "TASKLET : PCXHR_IRQ_NOTIFY event occurred\n");
+                       "PCXHR_IRQ_NOTIFY event occurred\n");
        if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) {
                /* clear events FREQ_CHANGE and TIME_CODE */
                pcxhr_init_rmh(prmh, CMD_TEST_IT);
        }
        if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) {
                dev_dbg(&mgr->pci->dev,
-                       "TASKLET : PCXHR_IRQ_ASYNC event occurred\n");
+                       "PCXHR_IRQ_ASYNC event occurred\n");
 
                pcxhr_init_rmh(prmh, CMD_ASYNC);
                prmh->cmd[0] |= 1;      /* add SEL_ASYNC_EVENTS */
                prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS;
                err = pcxhr_send_msg(mgr, prmh);
                if (err)
-                       dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_tasklet=%x;\n",
+                       dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_thread=%x;\n",
                                   err);
                i = 1;
                while (i < prmh->stat_len) {
                }
 
                if (elapsed) {
-                       spin_unlock(&mgr->lock);
+                       mutex_unlock(&mgr->lock);
                        snd_pcm_period_elapsed(stream->substream);
-                       spin_lock(&mgr->lock);
+                       mutex_lock(&mgr->lock);
                }
        }
 }
 {
        struct pcxhr_mgr *mgr = dev_id;
        unsigned int reg;
-       int i, j;
-       struct snd_pcxhr *chip;
-
-       spin_lock(&mgr->lock);
+       bool wake_thread = false;
 
        reg = PCXHR_INPL(mgr, PCXHR_PLX_IRQCS);
        if (! (reg & PCXHR_IRQCS_ACTIVE_PCIDB)) {
-               spin_unlock(&mgr->lock);
                /* this device did not cause the interrupt */
                return IRQ_NONE;
        }
        /* timer irq occurred */
        if (reg & PCXHR_IRQ_TIMER) {
                int timer_toggle = reg & PCXHR_IRQ_TIMER;
+               if (timer_toggle == mgr->timer_toggle) {
+                       dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n");
+                       mgr->dsp_time_err++;
+               }
+
+               mgr->timer_toggle = timer_toggle;
+               mgr->src_it_dsp = reg;
+               wake_thread = true;
+       }
+
+       /* other irq's handled in the thread */
+       if (reg & PCXHR_IRQ_MASK) {
+               if (reg & PCXHR_IRQ_ASYNC) {
+                       /* as we didn't request any async notifications,
+                        * some kind of xrun error will probably occurred
+                        */
+                       /* better resynchronize all streams next interrupt : */
+                       mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
+               }
+               mgr->src_it_dsp = reg;
+               wake_thread = true;
+       }
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+       if (reg & PCXHR_FATAL_DSP_ERR)
+               dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg);
+#endif
+
+       return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
+}
+
+irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id)
+{
+       struct pcxhr_mgr *mgr = dev_id;
+       int i, j;
+       struct snd_pcxhr *chip;
+
+       mutex_lock(&mgr->lock);
+       if (mgr->src_it_dsp & PCXHR_IRQ_TIMER) {
                /* is a 24 bit counter */
                int dsp_time_new =
                        PCXHR_INPL(mgr, PCXHR_PLX_MBOX4) & PCXHR_DSP_TIME_MASK;
 #endif
                mgr->dsp_time_last = dsp_time_new;
 
-               if (timer_toggle == mgr->timer_toggle) {
-                       dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n");
-                       mgr->dsp_time_err++;
-               }
-               mgr->timer_toggle = timer_toggle;
-
-               reg &= ~PCXHR_IRQ_TIMER;
                for (i = 0; i < mgr->num_cards; i++) {
                        chip = mgr->chip[i];
                        for (j = 0; j < chip->nb_streams_capt; j++)
                                                dsp_time_diff);
                }
        }
-       /* other irq's handled in the tasklet */
-       if (reg & PCXHR_IRQ_MASK) {
-               if (reg & PCXHR_IRQ_ASYNC) {
-                       /* as we didn't request any async notifications,
-                        * some kind of xrun error will probably occurred
-                        */
-                       /* better resynchronize all streams next interrupt : */
-                       mgr->dsp_time_last = PCXHR_DSP_TIME_INVALID;
-               }
-               mgr->src_it_dsp = reg;
-               tasklet_schedule(&mgr->msg_taskq);
-       }
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-       if (reg & PCXHR_FATAL_DSP_ERR)
-               dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg);
-#endif
-       spin_unlock(&mgr->lock);
-       return IRQ_HANDLED;     /* this device caused the interrupt */
+
+       pcxhr_msg_thread(mgr);
+       return IRQ_HANDLED;
 }
 
 
 /* interrupt handling */
 irqreturn_t pcxhr_interrupt(int irq, void *dev_id);
-void pcxhr_msg_tasklet(unsigned long arg);
+irqreturn_t pcxhr_threaded_irq(int irq, void *dev_id);
 
 #endif /* __SOUND_PCXHR_CORE_H */