aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/pcxhr/pcxhr_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/pcxhr/pcxhr_core.c')
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c102
1 files changed, 56 insertions, 46 deletions
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index df9371918601..a584acb61c00 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -767,11 +767,11 @@ void pcxhr_set_pipe_cmd_params(struct pcxhr_rmh *rmh, int capture,
*/
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;
}
@@ -971,17 +971,16 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
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);
@@ -996,7 +995,7 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask,
if (changed)
*changed = 1;
}
- spin_unlock_irqrestore(&mgr->msg_lock, flags);
+ mutex_unlock(&mgr->msg_lock);
return err;
}
@@ -1043,22 +1042,21 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 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);
@@ -1068,7 +1066,7 @@ void pcxhr_msg_tasklet(unsigned long arg)
}
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 */
@@ -1076,7 +1074,7 @@ void pcxhr_msg_tasklet(unsigned long arg)
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) {
@@ -1220,9 +1218,9 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr,
}
if (elapsed) {
- spin_unlock(&mgr->lock);
+ mutex_unlock(&mgr->lock);
snd_pcm_period_elapsed(stream->substream);
- spin_lock(&mgr->lock);
+ mutex_lock(&mgr->lock);
}
}
}
@@ -1231,14 +1229,10 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
{
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;
}
@@ -1250,6 +1244,44 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
/* 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;
@@ -1290,13 +1322,6 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
#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++)
@@ -1312,22 +1337,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id)
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;
}