diff options
-rw-r--r-- | sound/pci/oxygen/oxygen.h | 2 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_io.c | 24 | ||||
-rw-r--r-- | sound/pci/oxygen/oxygen_lib.c | 13 |
3 files changed, 28 insertions, 11 deletions
diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 8fc9e7ca1182..55ce2448805d 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <linux/mutex.h> | 4 | #include <linux/mutex.h> |
5 | #include <linux/spinlock.h> | 5 | #include <linux/spinlock.h> |
6 | #include <linux/wait.h> | ||
6 | #include <linux/workqueue.h> | 7 | #include <linux/workqueue.h> |
7 | #include "oxygen_regs.h" | 8 | #include "oxygen_regs.h" |
8 | 9 | ||
@@ -65,6 +66,7 @@ struct oxygen { | |||
65 | struct snd_pcm_substream *streams[PCM_COUNT]; | 66 | struct snd_pcm_substream *streams[PCM_COUNT]; |
66 | struct snd_kcontrol *controls[CONTROL_COUNT]; | 67 | struct snd_kcontrol *controls[CONTROL_COUNT]; |
67 | struct work_struct spdif_input_bits_work; | 68 | struct work_struct spdif_input_bits_work; |
69 | wait_queue_head_t ac97_waitqueue; | ||
68 | }; | 70 | }; |
69 | 71 | ||
70 | struct oxygen_model { | 72 | struct oxygen_model { |
diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c index d0cdce041dd8..74e23ef9c946 100644 --- a/sound/pci/oxygen/oxygen_io.c +++ b/sound/pci/oxygen/oxygen_io.c | |||
@@ -85,14 +85,22 @@ EXPORT_SYMBOL(oxygen_write32_masked); | |||
85 | 85 | ||
86 | static int oxygen_ac97_wait(struct oxygen *chip, unsigned int mask) | 86 | static int oxygen_ac97_wait(struct oxygen *chip, unsigned int mask) |
87 | { | 87 | { |
88 | unsigned long timeout = jiffies + msecs_to_jiffies(1); | 88 | u8 status = 0; |
89 | do { | 89 | |
90 | udelay(5); | 90 | /* |
91 | cond_resched(); | 91 | * Reading the status register also clears the bits, so we have to save |
92 | if (oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS) & mask) | 92 | * the read bits in status. |
93 | return 0; | 93 | */ |
94 | } while (time_after_eq(timeout, jiffies)); | 94 | wait_event_timeout(chip->ac97_waitqueue, |
95 | return -EIO; | 95 | ({ status |= oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS); |
96 | status & mask; }), | ||
97 | msecs_to_jiffies(1) + 1); | ||
98 | /* | ||
99 | * Check even after a timeout because this function should not require | ||
100 | * the AC'97 interrupt to be enabled. | ||
101 | */ | ||
102 | status |= oxygen_read8(chip, OXYGEN_AC97_INTERRUPT_STATUS); | ||
103 | return status & mask ? 0 : -EIO; | ||
96 | } | 104 | } |
97 | 105 | ||
98 | /* | 106 | /* |
diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index d98867c1f2d4..de6bf41c3e96 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c | |||
@@ -53,7 +53,8 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) | |||
53 | OXYGEN_CHANNEL_MULTICH | | 53 | OXYGEN_CHANNEL_MULTICH | |
54 | OXYGEN_CHANNEL_AC97 | | 54 | OXYGEN_CHANNEL_AC97 | |
55 | OXYGEN_INT_SPDIF_IN_DETECT | | 55 | OXYGEN_INT_SPDIF_IN_DETECT | |
56 | OXYGEN_INT_GPIO); | 56 | OXYGEN_INT_GPIO | |
57 | OXYGEN_INT_AC97); | ||
57 | if (clear) { | 58 | if (clear) { |
58 | if (clear & OXYGEN_INT_SPDIF_IN_DETECT) | 59 | if (clear & OXYGEN_INT_SPDIF_IN_DETECT) |
59 | chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT; | 60 | chip->interrupt_mask &= ~OXYGEN_INT_SPDIF_IN_DETECT; |
@@ -89,6 +90,9 @@ static irqreturn_t oxygen_interrupt(int dummy, void *dev_id) | |||
89 | if ((status & OXYGEN_INT_MIDI) && chip->midi) | 90 | if ((status & OXYGEN_INT_MIDI) && chip->midi) |
90 | snd_mpu401_uart_interrupt(0, chip->midi->private_data); | 91 | snd_mpu401_uart_interrupt(0, chip->midi->private_data); |
91 | 92 | ||
93 | if (status & OXYGEN_INT_AC97) | ||
94 | wake_up(&chip->ac97_waitqueue); | ||
95 | |||
92 | return IRQ_HANDLED; | 96 | return IRQ_HANDLED; |
93 | } | 97 | } |
94 | 98 | ||
@@ -306,7 +310,9 @@ static void __devinit oxygen_init(struct oxygen *chip) | |||
306 | (2 << OXYGEN_A_MONITOR_ROUTE_2_SHIFT) | | 310 | (2 << OXYGEN_A_MONITOR_ROUTE_2_SHIFT) | |
307 | (3 << OXYGEN_A_MONITOR_ROUTE_3_SHIFT)); | 311 | (3 << OXYGEN_A_MONITOR_ROUTE_3_SHIFT)); |
308 | 312 | ||
309 | oxygen_write8(chip, OXYGEN_AC97_INTERRUPT_MASK, 0); | 313 | oxygen_write8(chip, OXYGEN_AC97_INTERRUPT_MASK, |
314 | OXYGEN_AC97_INT_READ_DONE | | ||
315 | OXYGEN_AC97_INT_WRITE_DONE); | ||
310 | oxygen_write32(chip, OXYGEN_AC97_OUT_CONFIG, 0); | 316 | oxygen_write32(chip, OXYGEN_AC97_OUT_CONFIG, 0); |
311 | oxygen_write32(chip, OXYGEN_AC97_IN_CONFIG, 0); | 317 | oxygen_write32(chip, OXYGEN_AC97_IN_CONFIG, 0); |
312 | if (!(chip->has_ac97_0 | chip->has_ac97_1)) | 318 | if (!(chip->has_ac97_0 | chip->has_ac97_1)) |
@@ -408,6 +414,7 @@ int __devinit oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | |||
408 | mutex_init(&chip->mutex); | 414 | mutex_init(&chip->mutex); |
409 | INIT_WORK(&chip->spdif_input_bits_work, | 415 | INIT_WORK(&chip->spdif_input_bits_work, |
410 | oxygen_spdif_input_bits_changed); | 416 | oxygen_spdif_input_bits_changed); |
417 | init_waitqueue_head(&chip->ac97_waitqueue); | ||
411 | 418 | ||
412 | err = pci_enable_device(pci); | 419 | err = pci_enable_device(pci); |
413 | if (err < 0) | 420 | if (err < 0) |
@@ -471,7 +478,7 @@ int __devinit oxygen_pci_probe(struct pci_dev *pci, int index, char *id, | |||
471 | oxygen_proc_init(chip); | 478 | oxygen_proc_init(chip); |
472 | 479 | ||
473 | spin_lock_irq(&chip->reg_lock); | 480 | spin_lock_irq(&chip->reg_lock); |
474 | chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT; | 481 | chip->interrupt_mask |= OXYGEN_INT_SPDIF_IN_DETECT | OXYGEN_INT_AC97; |
475 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | 482 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); |
476 | spin_unlock_irq(&chip->reg_lock); | 483 | spin_unlock_irq(&chip->reg_lock); |
477 | 484 | ||