diff options
Diffstat (limited to 'sound/mips')
-rw-r--r-- | sound/mips/au1x00.c | 300 |
1 files changed, 150 insertions, 150 deletions
diff --git a/sound/mips/au1x00.c b/sound/mips/au1x00.c index d08a42b24b1f..a8f9a3b6e73d 100644 --- a/sound/mips/au1x00.c +++ b/sound/mips/au1x00.c | |||
@@ -50,12 +50,7 @@ | |||
50 | MODULE_AUTHOR("Charles Eidsness <charles@cooper-street.com>"); | 50 | MODULE_AUTHOR("Charles Eidsness <charles@cooper-street.com>"); |
51 | MODULE_DESCRIPTION("Au1000 AC'97 ALSA Driver"); | 51 | MODULE_DESCRIPTION("Au1000 AC'97 ALSA Driver"); |
52 | MODULE_LICENSE("GPL"); | 52 | MODULE_LICENSE("GPL"); |
53 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) | ||
54 | MODULE_SUPPORTED_DEVICE("{{AMD,Au1000 AC'97}}"); | 53 | MODULE_SUPPORTED_DEVICE("{{AMD,Au1000 AC'97}}"); |
55 | #else | ||
56 | MODULE_CLASSES("{sound}"); | ||
57 | MODULE_DEVICES("{{AMD,Au1000 AC'97}}"); | ||
58 | #endif | ||
59 | 54 | ||
60 | #define PLAYBACK 0 | 55 | #define PLAYBACK 0 |
61 | #define CAPTURE 1 | 56 | #define CAPTURE 1 |
@@ -68,8 +63,6 @@ MODULE_DEVICES("{{AMD,Au1000 AC'97}}"); | |||
68 | #define READ_WAIT 2 | 63 | #define READ_WAIT 2 |
69 | #define RW_DONE 3 | 64 | #define RW_DONE 3 |
70 | 65 | ||
71 | DECLARE_WAIT_QUEUE_HEAD(ac97_command_wq); | ||
72 | |||
73 | typedef struct au1000_period au1000_period_t; | 66 | typedef struct au1000_period au1000_period_t; |
74 | struct au1000_period | 67 | struct au1000_period |
75 | { | 68 | { |
@@ -94,7 +87,8 @@ struct audio_stream { | |||
94 | int dma; | 87 | int dma; |
95 | spinlock_t dma_lock; | 88 | spinlock_t dma_lock; |
96 | au1000_period_t * buffer; | 89 | au1000_period_t * buffer; |
97 | unsigned long period_size; | 90 | unsigned int period_size; |
91 | unsigned int periods; | ||
98 | }; | 92 | }; |
99 | 93 | ||
100 | typedef struct snd_card_au1000 { | 94 | typedef struct snd_card_au1000 { |
@@ -109,11 +103,9 @@ typedef struct snd_card_au1000 { | |||
109 | audio_stream_t *stream[2]; /* playback & capture */ | 103 | audio_stream_t *stream[2]; /* playback & capture */ |
110 | } au1000_t; | 104 | } au1000_t; |
111 | 105 | ||
112 | static au1000_t *au1000 = NULL; | ||
113 | |||
114 | /*--------------------------- Local Functions --------------------------------*/ | 106 | /*--------------------------- Local Functions --------------------------------*/ |
115 | static void | 107 | static void |
116 | au1000_set_ac97_xmit_slots(long xmit_slots) | 108 | au1000_set_ac97_xmit_slots(au1000_t *au1000, long xmit_slots) |
117 | { | 109 | { |
118 | u32 volatile ac97_config; | 110 | u32 volatile ac97_config; |
119 | 111 | ||
@@ -126,7 +118,7 @@ au1000_set_ac97_xmit_slots(long xmit_slots) | |||
126 | } | 118 | } |
127 | 119 | ||
128 | static void | 120 | static void |
129 | au1000_set_ac97_recv_slots(long recv_slots) | 121 | au1000_set_ac97_recv_slots(au1000_t *au1000, long recv_slots) |
130 | { | 122 | { |
131 | u32 volatile ac97_config; | 123 | u32 volatile ac97_config; |
132 | 124 | ||
@@ -140,79 +132,92 @@ au1000_set_ac97_recv_slots(long recv_slots) | |||
140 | 132 | ||
141 | 133 | ||
142 | static void | 134 | static void |
143 | au1000_dma_stop(audio_stream_t *stream) | 135 | au1000_release_dma_link(audio_stream_t *stream) |
144 | { | 136 | { |
145 | unsigned long flags; | ||
146 | au1000_period_t * pointer; | 137 | au1000_period_t * pointer; |
147 | au1000_period_t * pointer_next; | 138 | au1000_period_t * pointer_next; |
148 | 139 | ||
149 | if (stream->buffer != NULL) { | 140 | stream->period_size = 0; |
150 | spin_lock_irqsave(&stream->dma_lock, flags); | 141 | stream->periods = 0; |
151 | disable_dma(stream->dma); | 142 | pointer = stream->buffer; |
152 | spin_unlock_irqrestore(&stream->dma_lock, flags); | 143 | if (! pointer) |
144 | return; | ||
145 | do { | ||
146 | pointer_next = pointer->next; | ||
147 | kfree(pointer); | ||
148 | pointer = pointer_next; | ||
149 | } while (pointer != stream->buffer); | ||
150 | stream->buffer = NULL; | ||
151 | } | ||
152 | |||
153 | static int | ||
154 | au1000_setup_dma_link(audio_stream_t *stream, unsigned int period_bytes, | ||
155 | unsigned int periods) | ||
156 | { | ||
157 | snd_pcm_substream_t *substream = stream->substream; | ||
158 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
159 | unsigned long dma_start; | ||
160 | int i; | ||
161 | |||
162 | dma_start = virt_to_phys(runtime->dma_area); | ||
153 | 163 | ||
154 | pointer = stream->buffer; | 164 | if (stream->period_size == period_bytes && |
155 | pointer_next = stream->buffer->next; | 165 | stream->periods == periods) |
166 | return 0; /* not changed */ | ||
156 | 167 | ||
157 | do { | 168 | au1000_release_dma_link(stream); |
158 | kfree(pointer); | ||
159 | pointer = pointer_next; | ||
160 | pointer_next = pointer->next; | ||
161 | } while (pointer != stream->buffer); | ||
162 | 169 | ||
163 | stream->buffer = NULL; | 170 | stream->period_size = period_bytes; |
171 | stream->periods = periods; | ||
172 | |||
173 | stream->buffer = kmalloc(sizeof(au1000_period_t), GFP_KERNEL); | ||
174 | if (! stream->buffer) | ||
175 | return -ENOMEM; | ||
176 | pointer = stream->buffer; | ||
177 | for (i = 0; i < periods; i++) { | ||
178 | pointer->start = (u32)(dma_start + (i * period_bytes)); | ||
179 | pointer->relative_end = (u32) (((i+1) * period_bytes) - 0x1); | ||
180 | if (i < periods - 1) { | ||
181 | pointer->next = kmalloc(sizeof(struct au1000_period), GFP_KERNEL); | ||
182 | if (! pointer->next) { | ||
183 | au1000_release_dma_link(stream); | ||
184 | return -ENOMEM; | ||
185 | } | ||
186 | pointer = pointer->next; | ||
187 | } | ||
164 | } | 188 | } |
189 | pointer->next = stream->buffer; | ||
190 | return 0; | ||
165 | } | 191 | } |
166 | 192 | ||
167 | static void | 193 | static void |
168 | au1000_dma_start(audio_stream_t *stream) | 194 | au1000_dma_stop(audio_stream_t *stream) |
169 | { | 195 | { |
170 | snd_pcm_substream_t *substream = stream->substream; | 196 | snd_assert(stream->buffer, return); |
171 | snd_pcm_runtime_t *runtime = substream->runtime; | 197 | disable_dma(stream->dma); |
198 | } | ||
172 | 199 | ||
173 | unsigned long flags, dma_start; | 200 | static void |
174 | int i; | 201 | au1000_dma_start(audio_stream_t *stream) |
175 | au1000_period_t * pointer; | 202 | { |
203 | snd_assert(stream->buffer, return); | ||
176 | 204 | ||
177 | if (stream->buffer == NULL) { | 205 | init_dma(stream->dma); |
178 | dma_start = virt_to_phys(runtime->dma_area); | 206 | if (get_dma_active_buffer(stream->dma) == 0) { |
179 | 207 | clear_dma_done0(stream->dma); | |
180 | stream->period_size = frames_to_bytes(runtime, | 208 | set_dma_addr0(stream->dma, stream->buffer->start); |
181 | runtime->period_size); | 209 | set_dma_count0(stream->dma, stream->period_size >> 1); |
182 | stream->buffer = kmalloc(sizeof(au1000_period_t), GFP_KERNEL); | 210 | set_dma_addr1(stream->dma, stream->buffer->next->start); |
183 | pointer = stream->buffer; | 211 | set_dma_count1(stream->dma, stream->period_size >> 1); |
184 | for (i = 0 ; i < runtime->periods ; i++) { | 212 | } else { |
185 | pointer->start = (u32)(dma_start + | 213 | clear_dma_done1(stream->dma); |
186 | (i * stream->period_size)); | 214 | set_dma_addr1(stream->dma, stream->buffer->start); |
187 | pointer->relative_end = (u32) | 215 | set_dma_count1(stream->dma, stream->period_size >> 1); |
188 | (((i+1) * stream->period_size) - 0x1); | 216 | set_dma_addr0(stream->dma, stream->buffer->next->start); |
189 | if ( i < runtime->periods - 1) { | 217 | set_dma_count0(stream->dma, stream->period_size >> 1); |
190 | pointer->next = kmalloc(sizeof(au1000_period_t) | ||
191 | , GFP_KERNEL); | ||
192 | pointer = pointer->next; | ||
193 | } | ||
194 | } | ||
195 | pointer->next = stream->buffer; | ||
196 | |||
197 | spin_lock_irqsave(&stream->dma_lock, flags); | ||
198 | init_dma(stream->dma); | ||
199 | if (get_dma_active_buffer(stream->dma) == 0) { | ||
200 | clear_dma_done0(stream->dma); | ||
201 | set_dma_addr0(stream->dma, stream->buffer->start); | ||
202 | set_dma_count0(stream->dma, stream->period_size >> 1); | ||
203 | set_dma_addr1(stream->dma, stream->buffer->next->start); | ||
204 | set_dma_count1(stream->dma, stream->period_size >> 1); | ||
205 | } else { | ||
206 | clear_dma_done1(stream->dma); | ||
207 | set_dma_addr1(stream->dma, stream->buffer->start); | ||
208 | set_dma_count1(stream->dma, stream->period_size >> 1); | ||
209 | set_dma_addr0(stream->dma, stream->buffer->next->start); | ||
210 | set_dma_count0(stream->dma, stream->period_size >> 1); | ||
211 | } | ||
212 | enable_dma_buffers(stream->dma); | ||
213 | start_dma(stream->dma); | ||
214 | spin_unlock_irqrestore(&stream->dma_lock, flags); | ||
215 | } | 218 | } |
219 | enable_dma_buffers(stream->dma); | ||
220 | start_dma(stream->dma); | ||
216 | } | 221 | } |
217 | 222 | ||
218 | static irqreturn_t | 223 | static irqreturn_t |
@@ -238,11 +243,9 @@ au1000_dma_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
238 | enable_dma_buffer1(stream->dma); | 243 | enable_dma_buffer1(stream->dma); |
239 | break; | 244 | break; |
240 | case (DMA_D0 | DMA_D1): | 245 | case (DMA_D0 | DMA_D1): |
241 | spin_unlock(&stream->dma_lock); | ||
242 | printk(KERN_ERR "DMA %d missed interrupt.\n",stream->dma); | 246 | printk(KERN_ERR "DMA %d missed interrupt.\n",stream->dma); |
243 | au1000_dma_stop(stream); | 247 | au1000_dma_stop(stream); |
244 | au1000_dma_start(stream); | 248 | au1000_dma_start(stream); |
245 | spin_lock(&stream->dma_lock); | ||
246 | break; | 249 | break; |
247 | case (~DMA_D0 & ~DMA_D1): | 250 | case (~DMA_D0 & ~DMA_D1): |
248 | printk(KERN_ERR "DMA %d empty irq.\n",stream->dma); | 251 | printk(KERN_ERR "DMA %d empty irq.\n",stream->dma); |
@@ -261,7 +264,7 @@ static snd_pcm_hw_constraint_list_t hw_constraints_rates = { | |||
261 | .mask = 0, | 264 | .mask = 0, |
262 | }; | 265 | }; |
263 | 266 | ||
264 | static snd_pcm_hardware_t snd_au1000 = | 267 | static snd_pcm_hardware_t snd_au1000_hw = |
265 | { | 268 | { |
266 | .info = (SNDRV_PCM_INFO_INTERLEAVED | \ | 269 | .info = (SNDRV_PCM_INFO_INTERLEAVED | \ |
267 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), | 270 | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), |
@@ -283,10 +286,12 @@ static snd_pcm_hardware_t snd_au1000 = | |||
283 | static int | 286 | static int |
284 | snd_au1000_playback_open(snd_pcm_substream_t * substream) | 287 | snd_au1000_playback_open(snd_pcm_substream_t * substream) |
285 | { | 288 | { |
289 | au1000_t *au1000 = substream->pcm->private_data; | ||
290 | |||
286 | au1000->stream[PLAYBACK]->substream = substream; | 291 | au1000->stream[PLAYBACK]->substream = substream; |
287 | au1000->stream[PLAYBACK]->buffer = NULL; | 292 | au1000->stream[PLAYBACK]->buffer = NULL; |
288 | substream->private_data = au1000->stream[PLAYBACK]; | 293 | substream->private_data = au1000->stream[PLAYBACK]; |
289 | substream->runtime->hw = snd_au1000; | 294 | substream->runtime->hw = snd_au1000_hw; |
290 | return (snd_pcm_hw_constraint_list(substream->runtime, 0, | 295 | return (snd_pcm_hw_constraint_list(substream->runtime, 0, |
291 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0); | 296 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0); |
292 | } | 297 | } |
@@ -294,10 +299,12 @@ snd_au1000_playback_open(snd_pcm_substream_t * substream) | |||
294 | static int | 299 | static int |
295 | snd_au1000_capture_open(snd_pcm_substream_t * substream) | 300 | snd_au1000_capture_open(snd_pcm_substream_t * substream) |
296 | { | 301 | { |
302 | au1000_t *au1000 = substream->pcm->private_data; | ||
303 | |||
297 | au1000->stream[CAPTURE]->substream = substream; | 304 | au1000->stream[CAPTURE]->substream = substream; |
298 | au1000->stream[CAPTURE]->buffer = NULL; | 305 | au1000->stream[CAPTURE]->buffer = NULL; |
299 | substream->private_data = au1000->stream[CAPTURE]; | 306 | substream->private_data = au1000->stream[CAPTURE]; |
300 | substream->runtime->hw = snd_au1000; | 307 | substream->runtime->hw = snd_au1000_hw; |
301 | return (snd_pcm_hw_constraint_list(substream->runtime, 0, | 308 | return (snd_pcm_hw_constraint_list(substream->runtime, 0, |
302 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0); | 309 | SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates) < 0); |
303 | 310 | ||
@@ -306,6 +313,8 @@ snd_au1000_capture_open(snd_pcm_substream_t * substream) | |||
306 | static int | 313 | static int |
307 | snd_au1000_playback_close(snd_pcm_substream_t * substream) | 314 | snd_au1000_playback_close(snd_pcm_substream_t * substream) |
308 | { | 315 | { |
316 | au1000_t *au1000 = substream->pcm->private_data; | ||
317 | |||
309 | au1000->stream[PLAYBACK]->substream = NULL; | 318 | au1000->stream[PLAYBACK]->substream = NULL; |
310 | return 0; | 319 | return 0; |
311 | } | 320 | } |
@@ -313,6 +322,8 @@ snd_au1000_playback_close(snd_pcm_substream_t * substream) | |||
313 | static int | 322 | static int |
314 | snd_au1000_capture_close(snd_pcm_substream_t * substream) | 323 | snd_au1000_capture_close(snd_pcm_substream_t * substream) |
315 | { | 324 | { |
325 | au1000_t *au1000 = substream->pcm->private_data; | ||
326 | |||
316 | au1000->stream[CAPTURE]->substream = NULL; | 327 | au1000->stream[CAPTURE]->substream = NULL; |
317 | return 0; | 328 | return 0; |
318 | } | 329 | } |
@@ -321,25 +332,36 @@ static int | |||
321 | snd_au1000_hw_params(snd_pcm_substream_t * substream, | 332 | snd_au1000_hw_params(snd_pcm_substream_t * substream, |
322 | snd_pcm_hw_params_t * hw_params) | 333 | snd_pcm_hw_params_t * hw_params) |
323 | { | 334 | { |
324 | return snd_pcm_lib_malloc_pages(substream, | 335 | audio_stream_t *stream = substream->private_data; |
325 | params_buffer_bytes(hw_params)); | 336 | int err; |
337 | |||
338 | err = snd_pcm_lib_malloc_pages(substream, | ||
339 | params_buffer_bytes(hw_params)); | ||
340 | if (err < 0) | ||
341 | return err; | ||
342 | return au1000_setup_dma_link(stream, | ||
343 | params_period_bytes(hw_params), | ||
344 | params_periods(hw_params)); | ||
326 | } | 345 | } |
327 | 346 | ||
328 | static int | 347 | static int |
329 | snd_au1000_hw_free(snd_pcm_substream_t * substream) | 348 | snd_au1000_hw_free(snd_pcm_substream_t * substream) |
330 | { | 349 | { |
350 | audio_stream_t *stream = substream->private_data; | ||
351 | au1000_release_dma_link(stream); | ||
331 | return snd_pcm_lib_free_pages(substream); | 352 | return snd_pcm_lib_free_pages(substream); |
332 | } | 353 | } |
333 | 354 | ||
334 | static int | 355 | static int |
335 | snd_au1000_playback_prepare(snd_pcm_substream_t * substream) | 356 | snd_au1000_playback_prepare(snd_pcm_substream_t * substream) |
336 | { | 357 | { |
358 | au1000_t *au1000 = substream->pcm->private_data; | ||
337 | snd_pcm_runtime_t *runtime = substream->runtime; | 359 | snd_pcm_runtime_t *runtime = substream->runtime; |
338 | 360 | ||
339 | if (runtime->channels == 1 ) | 361 | if (runtime->channels == 1) |
340 | au1000_set_ac97_xmit_slots(AC97_SLOT_4); | 362 | au1000_set_ac97_xmit_slots(au1000, AC97_SLOT_4); |
341 | else | 363 | else |
342 | au1000_set_ac97_xmit_slots(AC97_SLOT_3 | AC97_SLOT_4); | 364 | au1000_set_ac97_xmit_slots(au1000, AC97_SLOT_3 | AC97_SLOT_4); |
343 | snd_ac97_set_rate(au1000->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate); | 365 | snd_ac97_set_rate(au1000->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate); |
344 | return 0; | 366 | return 0; |
345 | } | 367 | } |
@@ -347,12 +369,13 @@ snd_au1000_playback_prepare(snd_pcm_substream_t * substream) | |||
347 | static int | 369 | static int |
348 | snd_au1000_capture_prepare(snd_pcm_substream_t * substream) | 370 | snd_au1000_capture_prepare(snd_pcm_substream_t * substream) |
349 | { | 371 | { |
372 | au1000_t *au1000 = substream->pcm->private_data; | ||
350 | snd_pcm_runtime_t *runtime = substream->runtime; | 373 | snd_pcm_runtime_t *runtime = substream->runtime; |
351 | 374 | ||
352 | if (runtime->channels == 1 ) | 375 | if (runtime->channels == 1) |
353 | au1000_set_ac97_recv_slots(AC97_SLOT_4); | 376 | au1000_set_ac97_recv_slots(au1000, AC97_SLOT_4); |
354 | else | 377 | else |
355 | au1000_set_ac97_recv_slots(AC97_SLOT_3 | AC97_SLOT_4); | 378 | au1000_set_ac97_recv_slots(au1000, AC97_SLOT_3 | AC97_SLOT_4); |
356 | snd_ac97_set_rate(au1000->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); | 379 | snd_ac97_set_rate(au1000->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate); |
357 | return 0; | 380 | return 0; |
358 | } | 381 | } |
@@ -363,6 +386,7 @@ snd_au1000_trigger(snd_pcm_substream_t * substream, int cmd) | |||
363 | audio_stream_t *stream = substream->private_data; | 386 | audio_stream_t *stream = substream->private_data; |
364 | int err = 0; | 387 | int err = 0; |
365 | 388 | ||
389 | spin_lock(&stream->dma_lock); | ||
366 | switch (cmd) { | 390 | switch (cmd) { |
367 | case SNDRV_PCM_TRIGGER_START: | 391 | case SNDRV_PCM_TRIGGER_START: |
368 | au1000_dma_start(stream); | 392 | au1000_dma_start(stream); |
@@ -374,6 +398,7 @@ snd_au1000_trigger(snd_pcm_substream_t * substream, int cmd) | |||
374 | err = -EINVAL; | 398 | err = -EINVAL; |
375 | break; | 399 | break; |
376 | } | 400 | } |
401 | spin_unlock(&stream->dma_lock); | ||
377 | return err; | 402 | return err; |
378 | } | 403 | } |
379 | 404 | ||
@@ -382,12 +407,11 @@ snd_au1000_pointer(snd_pcm_substream_t * substream) | |||
382 | { | 407 | { |
383 | audio_stream_t *stream = substream->private_data; | 408 | audio_stream_t *stream = substream->private_data; |
384 | snd_pcm_runtime_t *runtime = substream->runtime; | 409 | snd_pcm_runtime_t *runtime = substream->runtime; |
385 | unsigned long flags; | ||
386 | long location; | 410 | long location; |
387 | 411 | ||
388 | spin_lock_irqsave(&stream->dma_lock, flags); | 412 | spin_lock(&stream->dma_lock); |
389 | location = get_dma_residue(stream->dma); | 413 | location = get_dma_residue(stream->dma); |
390 | spin_unlock_irqrestore(&stream->dma_lock, flags); | 414 | spin_unlock(&stream->dma_lock); |
391 | location = stream->buffer->relative_end - location; | 415 | location = stream->buffer->relative_end - location; |
392 | if (location == -1) | 416 | if (location == -1) |
393 | location = 0; | 417 | location = 0; |
@@ -438,6 +462,9 @@ snd_au1000_pcm_new(void) | |||
438 | pcm->info_flags = 0; | 462 | pcm->info_flags = 0; |
439 | strcpy(pcm->name, "Au1000 AC97 PCM"); | 463 | strcpy(pcm->name, "Au1000 AC97 PCM"); |
440 | 464 | ||
465 | spin_lock_init(&au1000->stream[PLAYBACK]->dma_lock); | ||
466 | spin_lock_init(&au1000->stream[CAPTURE]->dma_lock); | ||
467 | |||
441 | flags = claim_dma_lock(); | 468 | flags = claim_dma_lock(); |
442 | if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX, | 469 | if ((au1000->stream[PLAYBACK]->dma = request_au1000_dma(DMA_ID_AC97C_TX, |
443 | "AC97 TX", au1000_dma_interrupt, SA_INTERRUPT, | 470 | "AC97 TX", au1000_dma_interrupt, SA_INTERRUPT, |
@@ -457,8 +484,6 @@ snd_au1000_pcm_new(void) | |||
457 | set_dma_mode(au1000->stream[CAPTURE]->dma, | 484 | set_dma_mode(au1000->stream[CAPTURE]->dma, |
458 | get_dma_mode(au1000->stream[CAPTURE]->dma) & ~DMA_NC); | 485 | get_dma_mode(au1000->stream[CAPTURE]->dma) & ~DMA_NC); |
459 | release_dma_lock(flags); | 486 | release_dma_lock(flags); |
460 | spin_lock_init(&au1000->stream[PLAYBACK]->dma_lock); | ||
461 | spin_lock_init(&au1000->stream[CAPTURE]->dma_lock); | ||
462 | au1000->pcm = pcm; | 487 | au1000->pcm = pcm; |
463 | return 0; | 488 | return 0; |
464 | } | 489 | } |
@@ -469,9 +494,11 @@ snd_au1000_pcm_new(void) | |||
469 | static unsigned short | 494 | static unsigned short |
470 | snd_au1000_ac97_read(ac97_t *ac97, unsigned short reg) | 495 | snd_au1000_ac97_read(ac97_t *ac97, unsigned short reg) |
471 | { | 496 | { |
497 | au1000_t *au1000 = ac97->private_data; | ||
472 | u32 volatile cmd; | 498 | u32 volatile cmd; |
473 | u16 volatile data; | 499 | u16 volatile data; |
474 | int i; | 500 | int i; |
501 | |||
475 | spin_lock(&au1000->ac97_lock); | 502 | spin_lock(&au1000->ac97_lock); |
476 | /* would rather use the interupt than this polling but it works and I can't | 503 | /* would rather use the interupt than this polling but it works and I can't |
477 | get the interupt driven case to work efficiently */ | 504 | get the interupt driven case to work efficiently */ |
@@ -505,8 +532,10 @@ get the interupt driven case to work efficiently */ | |||
505 | static void | 532 | static void |
506 | snd_au1000_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) | 533 | snd_au1000_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) |
507 | { | 534 | { |
535 | au1000_t *au1000 = ac97->private_data; | ||
508 | u32 cmd; | 536 | u32 cmd; |
509 | int i; | 537 | int i; |
538 | |||
510 | spin_lock(&au1000->ac97_lock); | 539 | spin_lock(&au1000->ac97_lock); |
511 | /* would rather use the interupt than this polling but it works and I can't | 540 | /* would rather use the interupt than this polling but it works and I can't |
512 | get the interupt driven case to work efficiently */ | 541 | get the interupt driven case to work efficiently */ |
@@ -522,28 +551,13 @@ get the interupt driven case to work efficiently */ | |||
522 | au1000->ac97_ioport->cmd = cmd; | 551 | au1000->ac97_ioport->cmd = cmd; |
523 | spin_unlock(&au1000->ac97_lock); | 552 | spin_unlock(&au1000->ac97_lock); |
524 | } | 553 | } |
525 | static void | ||
526 | snd_au1000_ac97_free(ac97_t *ac97) | ||
527 | { | ||
528 | au1000->ac97 = NULL; | ||
529 | } | ||
530 | 554 | ||
531 | static int __devinit | 555 | static int __devinit |
532 | snd_au1000_ac97_new(void) | 556 | snd_au1000_ac97_new(au1000_t *au1000) |
533 | { | 557 | { |
534 | int err; | 558 | int err; |
535 | |||
536 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) | ||
537 | ac97_bus_t *pbus; | ||
538 | ac97_template_t ac97; | ||
539 | static ac97_bus_ops_t ops = { | ||
540 | .write = snd_au1000_ac97_write, | ||
541 | .read = snd_au1000_ac97_read, | ||
542 | }; | ||
543 | #else | ||
544 | ac97_bus_t bus, *pbus; | 559 | ac97_bus_t bus, *pbus; |
545 | ac97_t ac97; | 560 | ac97_t ac97; |
546 | #endif | ||
547 | 561 | ||
548 | if ((au1000->ac97_res_port = request_region(AC97C_CONFIG, | 562 | if ((au1000->ac97_res_port = request_region(AC97C_CONFIG, |
549 | sizeof(au1000_ac97_reg_t), "Au1x00 AC97")) == NULL) { | 563 | sizeof(au1000_ac97_reg_t), "Au1x00 AC97")) == NULL) { |
@@ -554,8 +568,6 @@ snd_au1000_ac97_new(void) | |||
554 | 568 | ||
555 | spin_lock_init(&au1000->ac97_lock); | 569 | spin_lock_init(&au1000->ac97_lock); |
556 | 570 | ||
557 | spin_lock(&au1000->ac97_lock); | ||
558 | |||
559 | /* configure pins for AC'97 | 571 | /* configure pins for AC'97 |
560 | TODO: move to board_setup.c */ | 572 | TODO: move to board_setup.c */ |
561 | au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC); | 573 | au_writel(au_readl(SYS_PINFUNC) & ~0x02, SYS_PINFUNC); |
@@ -572,26 +584,16 @@ snd_au1000_ac97_new(void) | |||
572 | au1000->ac97_ioport->config = 0x0; | 584 | au1000->ac97_ioport->config = 0x0; |
573 | mdelay(5); | 585 | mdelay(5); |
574 | 586 | ||
575 | spin_unlock(&au1000->ac97_lock); | ||
576 | |||
577 | /* Initialise AC97 middle-layer */ | 587 | /* Initialise AC97 middle-layer */ |
578 | #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8) | ||
579 | if ((err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus)) < 0) | 588 | if ((err = snd_ac97_bus(au1000->card, 0, &ops, au1000, &pbus)) < 0) |
580 | return err; | 589 | return err; |
581 | #else | 590 | |
582 | memset(&bus, 0, sizeof(bus)); | ||
583 | bus.write = snd_au1000_ac97_write; | ||
584 | bus.read = snd_au1000_ac97_read; | ||
585 | if ((err = snd_ac97_bus(au1000->card, &bus, &pbus)) < 0) | ||
586 | return err; | ||
587 | #endif | ||
588 | memset(&ac97, 0, sizeof(ac97)); | 591 | memset(&ac97, 0, sizeof(ac97)); |
589 | ac97.private_data = au1000; | 592 | ac97.private_data = au1000; |
590 | ac97.private_free = snd_au1000_ac97_free; | ||
591 | if ((err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97)) < 0) | 593 | if ((err = snd_ac97_mixer(pbus, &ac97, &au1000->ac97)) < 0) |
592 | return err; | 594 | return err; |
593 | return 0; | ||
594 | 595 | ||
596 | return 0; | ||
595 | } | 597 | } |
596 | 598 | ||
597 | /*------------------------------ Setup / Destroy ----------------------------*/ | 599 | /*------------------------------ Setup / Destroy ----------------------------*/ |
@@ -599,6 +601,7 @@ snd_au1000_ac97_new(void) | |||
599 | void | 601 | void |
600 | snd_au1000_free(snd_card_t *card) | 602 | snd_au1000_free(snd_card_t *card) |
601 | { | 603 | { |
604 | au1000_t *au1000 = card->private_data; | ||
602 | 605 | ||
603 | if (au1000->ac97_res_port) { | 606 | if (au1000->ac97_res_port) { |
604 | /* put internal AC97 block into reset */ | 607 | /* put internal AC97 block into reset */ |
@@ -614,73 +617,70 @@ snd_au1000_free(snd_card_t *card) | |||
614 | free_au1000_dma(au1000->stream[CAPTURE]->dma); | 617 | free_au1000_dma(au1000->stream[CAPTURE]->dma); |
615 | 618 | ||
616 | kfree(au1000->stream[PLAYBACK]); | 619 | kfree(au1000->stream[PLAYBACK]); |
617 | au1000->stream[PLAYBACK] = NULL; | ||
618 | kfree(au1000->stream[CAPTURE]); | 620 | kfree(au1000->stream[CAPTURE]); |
619 | au1000->stream[CAPTURE] = NULL; | ||
620 | kfree(au1000); | ||
621 | au1000 = NULL; | ||
622 | |||
623 | } | 621 | } |
624 | 622 | ||
623 | |||
624 | static snd_card_t *au1000_card; | ||
625 | |||
625 | static int __init | 626 | static int __init |
626 | au1000_init(void) | 627 | au1000_init(void) |
627 | { | 628 | { |
628 | int err; | 629 | int err; |
630 | snd_card_t *card; | ||
631 | au1000_t *au1000; | ||
629 | 632 | ||
630 | au1000 = kmalloc(sizeof(au1000_t), GFP_KERNEL); | 633 | card = snd_card_new(-1, "AC97", THIS_MODULE, sizeof(au1000_t)); |
631 | if (au1000 == NULL) | 634 | if (card == NULL) |
632 | return -ENOMEM; | ||
633 | au1000->stream[PLAYBACK] = kmalloc(sizeof(audio_stream_t), GFP_KERNEL); | ||
634 | if (au1000->stream[PLAYBACK] == NULL) | ||
635 | return -ENOMEM; | ||
636 | au1000->stream[CAPTURE] = kmalloc(sizeof(audio_stream_t), GFP_KERNEL); | ||
637 | if (au1000->stream[CAPTURE] == NULL) | ||
638 | return -ENOMEM; | 635 | return -ENOMEM; |
636 | |||
637 | card->private_free = snd_au1000_free; | ||
638 | au1000 = card->private_data; | ||
639 | /* so that snd_au1000_free will work as intended */ | 639 | /* so that snd_au1000_free will work as intended */ |
640 | au1000->card = card; | ||
640 | au1000->stream[PLAYBACK]->dma = -1; | 641 | au1000->stream[PLAYBACK]->dma = -1; |
641 | au1000->stream[CAPTURE]->dma = -1; | 642 | au1000->stream[CAPTURE]->dma = -1; |
642 | au1000->ac97_res_port = NULL; | 643 | au1000->ac97_res_port = NULL; |
643 | 644 | au1000->stream[PLAYBACK] = kmalloc(sizeof(audio_stream_t), GFP_KERNEL); | |
644 | au1000->card = snd_card_new(-1, "AC97", THIS_MODULE, sizeof(au1000_t)); | 645 | au1000->stream[CAPTURE] = kmalloc(sizeof(audio_stream_t), GFP_KERNEL); |
645 | if (au1000->card == NULL) { | 646 | if (au1000->stream[PLAYBACK] == NULL || |
646 | snd_au1000_free(au1000->card); | 647 | au1000->stream[CAPTURE] == NULL) { |
648 | snd_card_free(card); | ||
647 | return -ENOMEM; | 649 | return -ENOMEM; |
648 | } | 650 | } |
649 | 651 | ||
650 | au1000->card->private_data = (au1000_t *)au1000; | 652 | if ((err = snd_au1000_ac97_new(au1000)) < 0 ) { |
651 | au1000->card->private_free = snd_au1000_free; | 653 | snd_card_free(card); |
652 | |||
653 | if ((err = snd_au1000_ac97_new()) < 0 ) { | ||
654 | snd_card_free(au1000->card); | ||
655 | return err; | 654 | return err; |
656 | } | 655 | } |
657 | 656 | ||
658 | if ((err = snd_au1000_pcm_new()) < 0) { | 657 | if ((err = snd_au1000_pcm_new(au1000)) < 0) { |
659 | snd_card_free(au1000->card); | 658 | snd_card_free(card); |
660 | return err; | 659 | return err; |
661 | } | 660 | } |
662 | 661 | ||
663 | strcpy(au1000->card->driver, "AMD-Au1000-AC97"); | 662 | strcpy(card->driver, "Au1000-AC97"); |
664 | strcpy(au1000->card->shortname, "Au1000-AC97"); | 663 | strcpy(card->shortname, "AMD Au1000-AC97"); |
665 | sprintf(au1000->card->longname, "AMD Au1000--AC97 ALSA Driver"); | 664 | sprintf(card->longname, "AMD Au1000--AC97 ALSA Driver"); |
666 | 665 | ||
667 | if ((err = snd_card_set_generic_dev(au1000->card)) < 0) { | 666 | if ((err = snd_card_set_generic_dev(card)) < 0) { |
668 | snd_card_free(au1000->card); | 667 | snd_card_free(card); |
669 | return err; | 668 | return err; |
670 | } | 669 | } |
671 | 670 | ||
672 | if ((err = snd_card_register(au1000->card)) < 0) { | 671 | if ((err = snd_card_register(card)) < 0) { |
673 | snd_card_free(au1000->card); | 672 | snd_card_free(card); |
674 | return err; | 673 | return err; |
675 | } | 674 | } |
676 | 675 | ||
677 | printk( KERN_INFO "ALSA AC97: Driver Initialized\n" ); | 676 | printk( KERN_INFO "ALSA AC97: Driver Initialized\n" ); |
677 | au1000_card = card; | ||
678 | return 0; | 678 | return 0; |
679 | } | 679 | } |
680 | 680 | ||
681 | static void __exit au1000_exit(void) | 681 | static void __exit au1000_exit(void) |
682 | { | 682 | { |
683 | snd_card_free(au1000->card); | 683 | snd_card_free(au1000_card); |
684 | } | 684 | } |
685 | 685 | ||
686 | module_init(au1000_init); | 686 | module_init(au1000_init); |