aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJames Courtier-Dutton <James@superbug.co.uk>2007-11-10 12:55:14 -0500
committerJaroslav Kysela <perex@perex.cz>2008-01-31 11:30:24 -0500
commitc94fa4c9168e51a8dab8e72cb9f0d89673fc8d8c (patch)
tree08169553a3b69a284b322941131f406661e499e8
parent3839e4f136d6da3dc85d237aa9569ee94bfea763 (diff)
[ALSA] emu10k1: General cleanup, add new locks, fix alsa bug#3501, kernel bug#9304.
Signed-off-by: James Courtier-Dutton <James@superbug.co.uk> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r--include/sound/emu10k1.h2
-rw-r--r--sound/pci/emu10k1/emu10k1_callback.c15
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c6
-rw-r--r--sound/pci/emu10k1/emu10k1_synth.c45
-rw-r--r--sound/pci/emu10k1/io.c52
-rw-r--r--sound/pci/emu10k1/irq.c8
6 files changed, 82 insertions, 46 deletions
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h
index 494648dd7073..7b7b9b13b4dd 100644
--- a/include/sound/emu10k1.h
+++ b/include/sound/emu10k1.h
@@ -1742,6 +1742,8 @@ struct snd_emu10k1 {
1742 spinlock_t reg_lock; 1742 spinlock_t reg_lock;
1743 spinlock_t emu_lock; 1743 spinlock_t emu_lock;
1744 spinlock_t voice_lock; 1744 spinlock_t voice_lock;
1745 spinlock_t spi_lock; /* serialises access to spi port */
1746 spinlock_t i2c_lock; /* serialises access to i2c port */
1745 1747
1746 struct snd_emu10k1_voice voices[NUM_G]; 1748 struct snd_emu10k1_voice voices[NUM_G];
1747 struct snd_emu10k1_voice p16v_voices[4]; 1749 struct snd_emu10k1_voice p16v_voices[4];
diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c
index 01965bd99966..45088ebcce50 100644
--- a/sound/pci/emu10k1/emu10k1_callback.c
+++ b/sound/pci/emu10k1/emu10k1_callback.c
@@ -35,9 +35,9 @@ struct best_voice {
35/* 35/*
36 * prototypes 36 * prototypes
37 */ 37 */
38static void lookup_voices(struct snd_emux *emu, struct snd_emu10k1 *hw, 38static void lookup_voices(struct snd_emux *emux, struct snd_emu10k1 *hw,
39 struct best_voice *best, int active_only); 39 struct best_voice *best, int active_only);
40static struct snd_emux_voice *get_voice(struct snd_emux *emu, 40static struct snd_emux_voice *get_voice(struct snd_emux *emux,
41 struct snd_emux_port *port); 41 struct snd_emux_port *port);
42static int start_voice(struct snd_emux_voice *vp); 42static int start_voice(struct snd_emux_voice *vp);
43static void trigger_voice(struct snd_emux_voice *vp); 43static void trigger_voice(struct snd_emux_voice *vp);
@@ -45,7 +45,6 @@ static void release_voice(struct snd_emux_voice *vp);
45static void update_voice(struct snd_emux_voice *vp, int update); 45static void update_voice(struct snd_emux_voice *vp, int update);
46static void terminate_voice(struct snd_emux_voice *vp); 46static void terminate_voice(struct snd_emux_voice *vp);
47static void free_voice(struct snd_emux_voice *vp); 47static void free_voice(struct snd_emux_voice *vp);
48
49static void set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); 48static void set_fmmod(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
50static void set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); 49static void set_fm2frq2(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
51static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp); 50static void set_filterQ(struct snd_emu10k1 *hw, struct snd_emux_voice *vp);
@@ -75,9 +74,9 @@ static struct snd_emux_operators emu10k1_ops = {
75}; 74};
76 75
77void 76void
78snd_emu10k1_ops_setup(struct snd_emux *emu) 77snd_emu10k1_ops_setup(struct snd_emux *emux)
79{ 78{
80 emu->ops = emu10k1_ops; 79 emux->ops = emu10k1_ops;
81} 80}
82 81
83 82
@@ -166,7 +165,11 @@ free_voice(struct snd_emux_voice *vp)
166 struct snd_emu10k1 *hw; 165 struct snd_emu10k1 *hw;
167 166
168 hw = vp->hw; 167 hw = vp->hw;
169 if (vp->ch >= 0) { 168 /* FIXME: emu10k1_synth is broken. */
169 /* This can get called with hw == 0 */
170 /* Problem apparent on plug, unplug then plug */
171 /* on the Audigy 2 ZS Notebook. */
172 if (hw && (vp->ch >= 0)) {
170 snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00); 173 snd_emu10k1_ptr_write(hw, IFATN, vp->ch, 0xff00);
171 snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK); 174 snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0x807f | DCYSUSV_CHANNELENABLE_MASK);
172 // snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0); 175 // snd_emu10k1_ptr_write(hw, DCYSUSV, vp->ch, 0);
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 7e46325974a5..f29caf1afe06 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -259,7 +259,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
259 * GPIO7: Unknown 259 * GPIO7: Unknown
260 */ 260 */
261 outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ 261 outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */
262
263 } 262 }
264 if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */ 263 if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */
265 int size, n; 264 int size, n;
@@ -275,7 +274,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume)
275 emu->i2c_capture_volume[n][0]= 0xcf; 274 emu->i2c_capture_volume[n][0]= 0xcf;
276 emu->i2c_capture_volume[n][1]= 0xcf; 275 emu->i2c_capture_volume[n][1]= 0xcf;
277 } 276 }
278
279 } 277 }
280 278
281 279
@@ -653,6 +651,8 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 * emu)
653 value = inl(special_port); 651 value = inl(special_port);
654 652
655 snd_emu10k1_ptr20_write(emu, TINA2_VOLUME, 0, 0xfefefefe); /* Defaults to 0x30303030 */ 653 snd_emu10k1_ptr20_write(emu, TINA2_VOLUME, 0, 0xfefefefe); /* Defaults to 0x30303030 */
654 /* Delay to give time for ADC chip to switch on. It needs 113ms */
655 msleep(200);
656 return 0; 656 return 0;
657} 657}
658 658
@@ -1717,6 +1717,8 @@ int __devinit snd_emu10k1_create(struct snd_card *card,
1717 emu->card = card; 1717 emu->card = card;
1718 spin_lock_init(&emu->reg_lock); 1718 spin_lock_init(&emu->reg_lock);
1719 spin_lock_init(&emu->emu_lock); 1719 spin_lock_init(&emu->emu_lock);
1720 spin_lock_init(&emu->spi_lock);
1721 spin_lock_init(&emu->i2c_lock);
1720 spin_lock_init(&emu->voice_lock); 1722 spin_lock_init(&emu->voice_lock);
1721 spin_lock_init(&emu->synth_lock); 1723 spin_lock_init(&emu->synth_lock);
1722 spin_lock_init(&emu->memblk_lock); 1724 spin_lock_init(&emu->memblk_lock);
diff --git a/sound/pci/emu10k1/emu10k1_synth.c b/sound/pci/emu10k1/emu10k1_synth.c
index 204995a1dfbd..ad7b71491fc4 100644
--- a/sound/pci/emu10k1/emu10k1_synth.c
+++ b/sound/pci/emu10k1/emu10k1_synth.c
@@ -30,7 +30,7 @@ MODULE_LICENSE("GPL");
30 */ 30 */
31static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev) 31static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev)
32{ 32{
33 struct snd_emux *emu; 33 struct snd_emux *emux;
34 struct snd_emu10k1 *hw; 34 struct snd_emu10k1 *hw;
35 struct snd_emu10k1_synth_arg *arg; 35 struct snd_emu10k1_synth_arg *arg;
36 unsigned long flags; 36 unsigned long flags;
@@ -46,53 +46,56 @@ static int snd_emu10k1_synth_new_device(struct snd_seq_device *dev)
46 else if (arg->max_voices > 64) 46 else if (arg->max_voices > 64)
47 arg->max_voices = 64; 47 arg->max_voices = 64;
48 48
49 if (snd_emux_new(&emu) < 0) 49 if (snd_emux_new(&emux) < 0)
50 return -ENOMEM; 50 return -ENOMEM;
51 51
52 snd_emu10k1_ops_setup(emu); 52 snd_emu10k1_ops_setup(emux);
53 emu->hw = hw = arg->hwptr; 53 hw = arg->hwptr;
54 emu->max_voices = arg->max_voices; 54 emux->hw = hw;
55 emu->num_ports = arg->seq_ports; 55 emux->max_voices = arg->max_voices;
56 emu->pitch_shift = -501; 56 emux->num_ports = arg->seq_ports;
57 emu->memhdr = hw->memhdr; 57 emux->pitch_shift = -501;
58 emu->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2; /* maximum two ports */ 58 emux->memhdr = hw->memhdr;
59 emu->midi_devidx = hw->audigy ? 2 : 1; /* audigy has two external midis */ 59 /* maximum two ports */
60 emu->linear_panning = 0; 60 emux->midi_ports = arg->seq_ports < 2 ? arg->seq_ports : 2;
61 emu->hwdep_idx = 2; /* FIXED */ 61 /* audigy has two external midis */
62 62 emux->midi_devidx = hw->audigy ? 2 : 1;
63 if (snd_emux_register(emu, dev->card, arg->index, "Emu10k1") < 0) { 63 emux->linear_panning = 0;
64 snd_emux_free(emu); 64 emux->hwdep_idx = 2; /* FIXED */
65
66 if (snd_emux_register(emux, dev->card, arg->index, "Emu10k1") < 0) {
67 snd_emux_free(emux);
65 return -ENOMEM; 68 return -ENOMEM;
66 } 69 }
67 70
68 spin_lock_irqsave(&hw->voice_lock, flags); 71 spin_lock_irqsave(&hw->voice_lock, flags);
69 hw->synth = emu; 72 hw->synth = emux;
70 hw->get_synth_voice = snd_emu10k1_synth_get_voice; 73 hw->get_synth_voice = snd_emu10k1_synth_get_voice;
71 spin_unlock_irqrestore(&hw->voice_lock, flags); 74 spin_unlock_irqrestore(&hw->voice_lock, flags);
72 75
73 dev->driver_data = emu; 76 dev->driver_data = emux;
74 77
75 return 0; 78 return 0;
76} 79}
77 80
78static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev) 81static int snd_emu10k1_synth_delete_device(struct snd_seq_device *dev)
79{ 82{
80 struct snd_emux *emu; 83 struct snd_emux *emux;
81 struct snd_emu10k1 *hw; 84 struct snd_emu10k1 *hw;
82 unsigned long flags; 85 unsigned long flags;
83 86
84 if (dev->driver_data == NULL) 87 if (dev->driver_data == NULL)
85 return 0; /* not registered actually */ 88 return 0; /* not registered actually */
86 89
87 emu = dev->driver_data; 90 emux = dev->driver_data;
88 91
89 hw = emu->hw; 92 hw = emux->hw;
90 spin_lock_irqsave(&hw->voice_lock, flags); 93 spin_lock_irqsave(&hw->voice_lock, flags);
91 hw->synth = NULL; 94 hw->synth = NULL;
92 hw->get_synth_voice = NULL; 95 hw->get_synth_voice = NULL;
93 spin_unlock_irqrestore(&hw->voice_lock, flags); 96 spin_unlock_irqrestore(&hw->voice_lock, flags);
94 97
95 snd_emux_free(emu); 98 snd_emux_free(emux);
96 return 0; 99 return 0;
97} 100}
98 101
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c
index a02638350a0a..b5a802bdeb7c 100644
--- a/sound/pci/emu10k1/io.c
+++ b/sound/pci/emu10k1/io.c
@@ -70,6 +70,11 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i
70 unsigned long flags; 70 unsigned long flags;
71 unsigned int mask; 71 unsigned int mask;
72 72
73 if (!emu) {
74 snd_printk(KERN_ERR "ptr_write: emu is null!\n");
75 dump_stack();
76 return;
77 }
73 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; 78 mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK;
74 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); 79 regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK);
75 80
@@ -134,15 +139,23 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
134 unsigned int reset, set; 139 unsigned int reset, set;
135 unsigned int reg, tmp; 140 unsigned int reg, tmp;
136 int n, result; 141 int n, result;
142 int err = 0;
143
144 /* This function is not re-entrant, so protect against it. */
145 spin_lock(&emu->spi_lock);
137 if (emu->card_capabilities->ca0108_chip) 146 if (emu->card_capabilities->ca0108_chip)
138 reg = 0x3c; /* PTR20, reg 0x3c */ 147 reg = 0x3c; /* PTR20, reg 0x3c */
139 else { 148 else {
140 /* For other chip types the SPI register 149 /* For other chip types the SPI register
141 * is currently unknown. */ 150 * is currently unknown. */
142 return 1; 151 err = 1;
152 goto spi_write_exit;
153 }
154 if (data > 0xffff) {
155 /* Only 16bit values allowed */
156 err = 1;
157 goto spi_write_exit;
143 } 158 }
144 if (data > 0xffff) /* Only 16bit values allowed */
145 return 1;
146 159
147 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); 160 tmp = snd_emu10k1_ptr20_read(emu, reg, 0);
148 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */ 161 reset = (tmp & ~0x3ffff) | 0x20000; /* Set xxx20000 */
@@ -160,11 +173,17 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu,
160 break; 173 break;
161 } 174 }
162 } 175 }
163 if (result) /* Timed out */ 176 if (result) {
164 return 1; 177 /* Timed out */
178 err = 1;
179 goto spi_write_exit;
180 }
165 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data); 181 snd_emu10k1_ptr20_write(emu, reg, 0, reset | data);
166 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */ 182 tmp = snd_emu10k1_ptr20_read(emu, reg, 0); /* Write post */
167 return 0; 183 err = 0;
184spi_write_exit:
185 spin_unlock(&emu->spi_lock);
186 return err;
168} 187}
169 188
170/* The ADC does not support i2c read, so only write is implemented */ 189/* The ADC does not support i2c read, so only write is implemented */
@@ -176,15 +195,17 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
176 int timeout = 0; 195 int timeout = 0;
177 int status; 196 int status;
178 int retry; 197 int retry;
198 int err = 0;
199
179 if ((reg > 0x7f) || (value > 0x1ff)) { 200 if ((reg > 0x7f) || (value > 0x1ff)) {
180 snd_printk(KERN_ERR "i2c_write: invalid values.\n"); 201 snd_printk(KERN_ERR "i2c_write: invalid values.\n");
181 return -EINVAL; 202 return -EINVAL;
182 } 203 }
183 204
205 /* This function is not re-entrant, so protect against it. */
206 spin_lock(&emu->i2c_lock);
207
184 tmp = reg << 25 | value << 16; 208 tmp = reg << 25 | value << 16;
185 // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value);
186 /* Not sure what this I2C channel controls. */
187 /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */
188 209
189 /* This controls the I2C connected to the WM8775 ADC Codec */ 210 /* This controls the I2C connected to the WM8775 ADC Codec */
190 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); 211 snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp);
@@ -192,17 +213,14 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
192 213
193 for (retry = 0; retry < 10; retry++) { 214 for (retry = 0; retry < 10; retry++) {
194 /* Send the data to i2c */ 215 /* Send the data to i2c */
195 //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0);
196 //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK);
197 tmp = 0; 216 tmp = 0;
198 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); 217 tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD);
199 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); 218 snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp);
200 219
201 /* Wait till the transaction ends */ 220 /* Wait till the transaction ends */
202 while (1) { 221 while (1) {
203 udelay(10); 222 mdelay(1);
204 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); 223 status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0);
205 // snd_printk("I2C:status=0x%x\n", status);
206 timeout++; 224 timeout++;
207 if ((status & I2C_A_ADC_START) == 0) 225 if ((status & I2C_A_ADC_START) == 0)
208 break; 226 break;
@@ -219,10 +237,14 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu,
219 237
220 if (retry == 10) { 238 if (retry == 10) {
221 snd_printk(KERN_ERR "Writing to ADC failed!\n"); 239 snd_printk(KERN_ERR "Writing to ADC failed!\n");
222 return -EINVAL; 240 snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n",
241 status, reg, value);
242 /* dump_stack(); */
243 err = -EINVAL;
223 } 244 }
224 245
225 return 0; 246 spin_unlock(&emu->i2c_lock);
247 return err;
226} 248}
227 249
228int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) 250int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value)
diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c
index 276d08c88f91..30bfed6f8339 100644
--- a/sound/pci/emu10k1/irq.c
+++ b/sound/pci/emu10k1/irq.c
@@ -34,9 +34,10 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
34 struct snd_emu10k1 *emu = dev_id; 34 struct snd_emu10k1 *emu = dev_id;
35 unsigned int status, status2, orig_status, orig_status2; 35 unsigned int status, status2, orig_status, orig_status2;
36 int handled = 0; 36 int handled = 0;
37 int timeout = 0;
37 38
38 while ((status = inl(emu->port + IPR)) != 0) { 39 while (((status = inl(emu->port + IPR)) != 0) && (timeout < 1000)) {
39 //snd_printk(KERN_INFO "emu10k1 irq - status = 0x%x\n", status); 40 timeout++;
40 orig_status = status; 41 orig_status = status;
41 handled = 1; 42 handled = 1;
42 if ((status & 0xffffffff) == 0xffffffff) { 43 if ((status & 0xffffffff) == 0xffffffff) {
@@ -200,5 +201,8 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id)
200 } 201 }
201 outl(orig_status, emu->port + IPR); /* ack all */ 202 outl(orig_status, emu->port + IPR); /* ack all */
202 } 203 }
204 if (timeout == 1000)
205 snd_printk(KERN_INFO "emu10k1 irq routine failure\n");
206
203 return IRQ_RETVAL(handled); 207 return IRQ_RETVAL(handled);
204} 208}