diff options
Diffstat (limited to 'sound/aoa/soundbus/i2sbus/pcm.c')
-rw-r--r-- | sound/aoa/soundbus/i2sbus/pcm.c | 1062 |
1 files changed, 1062 insertions, 0 deletions
diff --git a/sound/aoa/soundbus/i2sbus/pcm.c b/sound/aoa/soundbus/i2sbus/pcm.c new file mode 100644 index 000000000000..59bacd365733 --- /dev/null +++ b/sound/aoa/soundbus/i2sbus/pcm.c | |||
@@ -0,0 +1,1062 @@ | |||
1 | /* | ||
2 | * i2sbus driver -- pcm routines | ||
3 | * | ||
4 | * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> | ||
5 | * | ||
6 | * GPL v2, can be found in COPYING. | ||
7 | */ | ||
8 | |||
9 | #include <asm/io.h> | ||
10 | #include <linux/delay.h> | ||
11 | #include <sound/core.h> | ||
12 | #include <asm/macio.h> | ||
13 | #include <linux/pci.h> | ||
14 | #include "../soundbus.h" | ||
15 | #include "i2sbus.h" | ||
16 | |||
17 | static inline void get_pcm_info(struct i2sbus_dev *i2sdev, int in, | ||
18 | struct pcm_info **pi, struct pcm_info **other) | ||
19 | { | ||
20 | if (in) { | ||
21 | if (pi) | ||
22 | *pi = &i2sdev->in; | ||
23 | if (other) | ||
24 | *other = &i2sdev->out; | ||
25 | } else { | ||
26 | if (pi) | ||
27 | *pi = &i2sdev->out; | ||
28 | if (other) | ||
29 | *other = &i2sdev->in; | ||
30 | } | ||
31 | } | ||
32 | |||
33 | static int clock_and_divisors(int mclk, int sclk, int rate, int *out) | ||
34 | { | ||
35 | /* sclk must be derived from mclk! */ | ||
36 | if (mclk % sclk) | ||
37 | return -1; | ||
38 | /* derive sclk register value */ | ||
39 | if (i2s_sf_sclkdiv(mclk / sclk, out)) | ||
40 | return -1; | ||
41 | |||
42 | if (I2S_CLOCK_SPEED_18MHz % (rate * mclk) == 0) { | ||
43 | if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_18MHz / (rate * mclk), out)) { | ||
44 | *out |= I2S_SF_CLOCK_SOURCE_18MHz; | ||
45 | return 0; | ||
46 | } | ||
47 | } | ||
48 | if (I2S_CLOCK_SPEED_45MHz % (rate * mclk) == 0) { | ||
49 | if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_45MHz / (rate * mclk), out)) { | ||
50 | *out |= I2S_SF_CLOCK_SOURCE_45MHz; | ||
51 | return 0; | ||
52 | } | ||
53 | } | ||
54 | if (I2S_CLOCK_SPEED_49MHz % (rate * mclk) == 0) { | ||
55 | if (!i2s_sf_mclkdiv(I2S_CLOCK_SPEED_49MHz / (rate * mclk), out)) { | ||
56 | *out |= I2S_SF_CLOCK_SOURCE_49MHz; | ||
57 | return 0; | ||
58 | } | ||
59 | } | ||
60 | return -1; | ||
61 | } | ||
62 | |||
63 | #define CHECK_RATE(rate) \ | ||
64 | do { if (rates & SNDRV_PCM_RATE_ ##rate) { \ | ||
65 | int dummy; \ | ||
66 | if (clock_and_divisors(sysclock_factor, \ | ||
67 | bus_factor, rate, &dummy)) \ | ||
68 | rates &= ~SNDRV_PCM_RATE_ ##rate; \ | ||
69 | } } while (0) | ||
70 | |||
71 | static int i2sbus_pcm_open(struct i2sbus_dev *i2sdev, int in) | ||
72 | { | ||
73 | struct pcm_info *pi, *other; | ||
74 | struct soundbus_dev *sdev; | ||
75 | int masks_inited = 0, err; | ||
76 | struct codec_info_item *cii, *rev; | ||
77 | struct snd_pcm_hardware *hw; | ||
78 | u64 formats = 0; | ||
79 | unsigned int rates = 0; | ||
80 | struct transfer_info v; | ||
81 | int result = 0; | ||
82 | int bus_factor = 0, sysclock_factor = 0; | ||
83 | int found_this; | ||
84 | |||
85 | mutex_lock(&i2sdev->lock); | ||
86 | |||
87 | get_pcm_info(i2sdev, in, &pi, &other); | ||
88 | |||
89 | hw = &pi->substream->runtime->hw; | ||
90 | sdev = &i2sdev->sound; | ||
91 | |||
92 | if (pi->active) { | ||
93 | /* alsa messed up */ | ||
94 | result = -EBUSY; | ||
95 | goto out_unlock; | ||
96 | } | ||
97 | |||
98 | /* we now need to assign the hw */ | ||
99 | list_for_each_entry(cii, &sdev->codec_list, list) { | ||
100 | struct transfer_info *ti = cii->codec->transfers; | ||
101 | bus_factor = cii->codec->bus_factor; | ||
102 | sysclock_factor = cii->codec->sysclock_factor; | ||
103 | while (ti->formats && ti->rates) { | ||
104 | v = *ti; | ||
105 | if (ti->transfer_in == in | ||
106 | && cii->codec->usable(cii, ti, &v)) { | ||
107 | if (masks_inited) { | ||
108 | formats &= v.formats; | ||
109 | rates &= v.rates; | ||
110 | } else { | ||
111 | formats = v.formats; | ||
112 | rates = v.rates; | ||
113 | masks_inited = 1; | ||
114 | } | ||
115 | } | ||
116 | ti++; | ||
117 | } | ||
118 | } | ||
119 | if (!masks_inited || !bus_factor || !sysclock_factor) { | ||
120 | result = -ENODEV; | ||
121 | goto out_unlock; | ||
122 | } | ||
123 | /* bus dependent stuff */ | ||
124 | hw->info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | | ||
125 | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_RESUME | | ||
126 | SNDRV_PCM_INFO_JOINT_DUPLEX; | ||
127 | |||
128 | CHECK_RATE(5512); | ||
129 | CHECK_RATE(8000); | ||
130 | CHECK_RATE(11025); | ||
131 | CHECK_RATE(16000); | ||
132 | CHECK_RATE(22050); | ||
133 | CHECK_RATE(32000); | ||
134 | CHECK_RATE(44100); | ||
135 | CHECK_RATE(48000); | ||
136 | CHECK_RATE(64000); | ||
137 | CHECK_RATE(88200); | ||
138 | CHECK_RATE(96000); | ||
139 | CHECK_RATE(176400); | ||
140 | CHECK_RATE(192000); | ||
141 | hw->rates = rates; | ||
142 | |||
143 | /* well. the codec might want 24 bits only, and we'll | ||
144 | * ever only transfer 24 bits, but they are top-aligned! | ||
145 | * So for alsa, we claim that we're doing full 32 bit | ||
146 | * while in reality we'll ignore the lower 8 bits of | ||
147 | * that when doing playback (they're transferred as 0 | ||
148 | * as far as I know, no codecs we have are 32-bit capable | ||
149 | * so I can't really test) and when doing recording we'll | ||
150 | * always have those lower 8 bits recorded as 0 */ | ||
151 | if (formats & SNDRV_PCM_FMTBIT_S24_BE) | ||
152 | formats |= SNDRV_PCM_FMTBIT_S32_BE; | ||
153 | if (formats & SNDRV_PCM_FMTBIT_U24_BE) | ||
154 | formats |= SNDRV_PCM_FMTBIT_U32_BE; | ||
155 | /* now mask off what we can support. I suppose we could | ||
156 | * also support S24_3LE and some similar formats, but I | ||
157 | * doubt there's a codec that would be able to use that, | ||
158 | * so we don't support it here. */ | ||
159 | hw->formats = formats & (SNDRV_PCM_FMTBIT_S16_BE | | ||
160 | SNDRV_PCM_FMTBIT_U16_BE | | ||
161 | SNDRV_PCM_FMTBIT_S32_BE | | ||
162 | SNDRV_PCM_FMTBIT_U32_BE); | ||
163 | |||
164 | /* we need to set the highest and lowest rate possible. | ||
165 | * These are the highest and lowest rates alsa can | ||
166 | * support properly in its bitfield. | ||
167 | * Below, we'll use that to restrict to the rate | ||
168 | * currently in use (if any). */ | ||
169 | hw->rate_min = 5512; | ||
170 | hw->rate_max = 192000; | ||
171 | /* if the other stream is active, then we can only | ||
172 | * support what it is currently using. | ||
173 | * FIXME: I lied. This comment is wrong. We can support | ||
174 | * anything that works with the same serial format, ie. | ||
175 | * when recording 24 bit sound we can well play 16 bit | ||
176 | * sound at the same time iff using the same transfer mode. | ||
177 | */ | ||
178 | if (other->active) { | ||
179 | /* FIXME: is this guaranteed by the alsa api? */ | ||
180 | hw->formats &= (1ULL << i2sdev->format); | ||
181 | /* see above, restrict rates to the one we already have */ | ||
182 | hw->rate_min = i2sdev->rate; | ||
183 | hw->rate_max = i2sdev->rate; | ||
184 | } | ||
185 | |||
186 | hw->channels_min = 2; | ||
187 | hw->channels_max = 2; | ||
188 | /* these are somewhat arbitrary */ | ||
189 | hw->buffer_bytes_max = 131072; | ||
190 | hw->period_bytes_min = 256; | ||
191 | hw->period_bytes_max = 16384; | ||
192 | hw->periods_min = 3; | ||
193 | hw->periods_max = MAX_DBDMA_COMMANDS; | ||
194 | err = snd_pcm_hw_constraint_integer(pi->substream->runtime, | ||
195 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
196 | if (err < 0) { | ||
197 | result = err; | ||
198 | goto out_unlock; | ||
199 | } | ||
200 | list_for_each_entry(cii, &sdev->codec_list, list) { | ||
201 | if (cii->codec->open) { | ||
202 | err = cii->codec->open(cii, pi->substream); | ||
203 | if (err) { | ||
204 | result = err; | ||
205 | /* unwind */ | ||
206 | found_this = 0; | ||
207 | list_for_each_entry_reverse(rev, | ||
208 | &sdev->codec_list, list) { | ||
209 | if (found_this && rev->codec->close) { | ||
210 | rev->codec->close(rev, | ||
211 | pi->substream); | ||
212 | } | ||
213 | if (rev == cii) | ||
214 | found_this = 1; | ||
215 | } | ||
216 | goto out_unlock; | ||
217 | } | ||
218 | } | ||
219 | } | ||
220 | |||
221 | out_unlock: | ||
222 | mutex_unlock(&i2sdev->lock); | ||
223 | return result; | ||
224 | } | ||
225 | |||
226 | #undef CHECK_RATE | ||
227 | |||
228 | static int i2sbus_pcm_close(struct i2sbus_dev *i2sdev, int in) | ||
229 | { | ||
230 | struct codec_info_item *cii; | ||
231 | struct pcm_info *pi; | ||
232 | int err = 0, tmp; | ||
233 | |||
234 | mutex_lock(&i2sdev->lock); | ||
235 | |||
236 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
237 | |||
238 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
239 | if (cii->codec->close) { | ||
240 | tmp = cii->codec->close(cii, pi->substream); | ||
241 | if (tmp) | ||
242 | err = tmp; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | pi->substream = NULL; | ||
247 | pi->active = 0; | ||
248 | mutex_unlock(&i2sdev->lock); | ||
249 | return err; | ||
250 | } | ||
251 | |||
252 | static void i2sbus_wait_for_stop(struct i2sbus_dev *i2sdev, | ||
253 | struct pcm_info *pi) | ||
254 | { | ||
255 | unsigned long flags; | ||
256 | struct completion done; | ||
257 | long timeout; | ||
258 | |||
259 | spin_lock_irqsave(&i2sdev->low_lock, flags); | ||
260 | if (pi->dbdma_ring.stopping) { | ||
261 | init_completion(&done); | ||
262 | pi->stop_completion = &done; | ||
263 | spin_unlock_irqrestore(&i2sdev->low_lock, flags); | ||
264 | timeout = wait_for_completion_timeout(&done, HZ); | ||
265 | spin_lock_irqsave(&i2sdev->low_lock, flags); | ||
266 | pi->stop_completion = NULL; | ||
267 | if (timeout == 0) { | ||
268 | /* timeout expired, stop dbdma forcefully */ | ||
269 | printk(KERN_ERR "i2sbus_wait_for_stop: timed out\n"); | ||
270 | /* make sure RUN, PAUSE and S0 bits are cleared */ | ||
271 | out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); | ||
272 | pi->dbdma_ring.stopping = 0; | ||
273 | timeout = 10; | ||
274 | while (in_le32(&pi->dbdma->status) & ACTIVE) { | ||
275 | if (--timeout <= 0) | ||
276 | break; | ||
277 | udelay(1); | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | spin_unlock_irqrestore(&i2sdev->low_lock, flags); | ||
282 | } | ||
283 | |||
284 | #ifdef CONFIG_PM | ||
285 | void i2sbus_wait_for_stop_both(struct i2sbus_dev *i2sdev) | ||
286 | { | ||
287 | struct pcm_info *pi; | ||
288 | |||
289 | get_pcm_info(i2sdev, 0, &pi, NULL); | ||
290 | i2sbus_wait_for_stop(i2sdev, pi); | ||
291 | get_pcm_info(i2sdev, 1, &pi, NULL); | ||
292 | i2sbus_wait_for_stop(i2sdev, pi); | ||
293 | } | ||
294 | #endif | ||
295 | |||
296 | static int i2sbus_hw_params(struct snd_pcm_substream *substream, | ||
297 | struct snd_pcm_hw_params *params) | ||
298 | { | ||
299 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); | ||
300 | } | ||
301 | |||
302 | static inline int i2sbus_hw_free(struct snd_pcm_substream *substream, int in) | ||
303 | { | ||
304 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
305 | struct pcm_info *pi; | ||
306 | |||
307 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
308 | if (pi->dbdma_ring.stopping) | ||
309 | i2sbus_wait_for_stop(i2sdev, pi); | ||
310 | snd_pcm_lib_free_pages(substream); | ||
311 | return 0; | ||
312 | } | ||
313 | |||
314 | static int i2sbus_playback_hw_free(struct snd_pcm_substream *substream) | ||
315 | { | ||
316 | return i2sbus_hw_free(substream, 0); | ||
317 | } | ||
318 | |||
319 | static int i2sbus_record_hw_free(struct snd_pcm_substream *substream) | ||
320 | { | ||
321 | return i2sbus_hw_free(substream, 1); | ||
322 | } | ||
323 | |||
324 | static int i2sbus_pcm_prepare(struct i2sbus_dev *i2sdev, int in) | ||
325 | { | ||
326 | /* whee. Hard work now. The user has selected a bitrate | ||
327 | * and bit format, so now we have to program our | ||
328 | * I2S controller appropriately. */ | ||
329 | struct snd_pcm_runtime *runtime; | ||
330 | struct dbdma_cmd *command; | ||
331 | int i, periodsize, nperiods; | ||
332 | dma_addr_t offset; | ||
333 | struct bus_info bi; | ||
334 | struct codec_info_item *cii; | ||
335 | int sfr = 0; /* serial format register */ | ||
336 | int dws = 0; /* data word sizes reg */ | ||
337 | int input_16bit; | ||
338 | struct pcm_info *pi, *other; | ||
339 | int cnt; | ||
340 | int result = 0; | ||
341 | unsigned int cmd, stopaddr; | ||
342 | |||
343 | mutex_lock(&i2sdev->lock); | ||
344 | |||
345 | get_pcm_info(i2sdev, in, &pi, &other); | ||
346 | |||
347 | if (pi->dbdma_ring.running) { | ||
348 | result = -EBUSY; | ||
349 | goto out_unlock; | ||
350 | } | ||
351 | if (pi->dbdma_ring.stopping) | ||
352 | i2sbus_wait_for_stop(i2sdev, pi); | ||
353 | |||
354 | if (!pi->substream || !pi->substream->runtime) { | ||
355 | result = -EINVAL; | ||
356 | goto out_unlock; | ||
357 | } | ||
358 | |||
359 | runtime = pi->substream->runtime; | ||
360 | pi->active = 1; | ||
361 | if (other->active && | ||
362 | ((i2sdev->format != runtime->format) | ||
363 | || (i2sdev->rate != runtime->rate))) { | ||
364 | result = -EINVAL; | ||
365 | goto out_unlock; | ||
366 | } | ||
367 | |||
368 | i2sdev->format = runtime->format; | ||
369 | i2sdev->rate = runtime->rate; | ||
370 | |||
371 | periodsize = snd_pcm_lib_period_bytes(pi->substream); | ||
372 | nperiods = pi->substream->runtime->periods; | ||
373 | pi->current_period = 0; | ||
374 | |||
375 | /* generate dbdma command ring first */ | ||
376 | command = pi->dbdma_ring.cmds; | ||
377 | memset(command, 0, (nperiods + 2) * sizeof(struct dbdma_cmd)); | ||
378 | |||
379 | /* commands to DMA to/from the ring */ | ||
380 | /* | ||
381 | * For input, we need to do a graceful stop; if we abort | ||
382 | * the DMA, we end up with leftover bytes that corrupt | ||
383 | * the next recording. To do this we set the S0 status | ||
384 | * bit and wait for the DMA controller to stop. Each | ||
385 | * command has a branch condition to | ||
386 | * make it branch to a stop command if S0 is set. | ||
387 | * On input we also need to wait for the S7 bit to be | ||
388 | * set before turning off the DMA controller. | ||
389 | * In fact we do the graceful stop for output as well. | ||
390 | */ | ||
391 | offset = runtime->dma_addr; | ||
392 | cmd = (in? INPUT_MORE: OUTPUT_MORE) | BR_IFSET | INTR_ALWAYS; | ||
393 | stopaddr = pi->dbdma_ring.bus_cmd_start + | ||
394 | (nperiods + 1) * sizeof(struct dbdma_cmd); | ||
395 | for (i = 0; i < nperiods; i++, command++, offset += periodsize) { | ||
396 | command->command = cpu_to_le16(cmd); | ||
397 | command->cmd_dep = cpu_to_le32(stopaddr); | ||
398 | command->phy_addr = cpu_to_le32(offset); | ||
399 | command->req_count = cpu_to_le16(periodsize); | ||
400 | } | ||
401 | |||
402 | /* branch back to beginning of ring */ | ||
403 | command->command = cpu_to_le16(DBDMA_NOP | BR_ALWAYS); | ||
404 | command->cmd_dep = cpu_to_le32(pi->dbdma_ring.bus_cmd_start); | ||
405 | command++; | ||
406 | |||
407 | /* set stop command */ | ||
408 | command->command = cpu_to_le16(DBDMA_STOP); | ||
409 | |||
410 | /* ok, let's set the serial format and stuff */ | ||
411 | switch (runtime->format) { | ||
412 | /* 16 bit formats */ | ||
413 | case SNDRV_PCM_FORMAT_S16_BE: | ||
414 | case SNDRV_PCM_FORMAT_U16_BE: | ||
415 | /* FIXME: if we add different bus factors we need to | ||
416 | * do more here!! */ | ||
417 | bi.bus_factor = 0; | ||
418 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
419 | bi.bus_factor = cii->codec->bus_factor; | ||
420 | break; | ||
421 | } | ||
422 | if (!bi.bus_factor) { | ||
423 | result = -ENODEV; | ||
424 | goto out_unlock; | ||
425 | } | ||
426 | input_16bit = 1; | ||
427 | break; | ||
428 | case SNDRV_PCM_FORMAT_S32_BE: | ||
429 | case SNDRV_PCM_FORMAT_U32_BE: | ||
430 | /* force 64x bus speed, otherwise the data cannot be | ||
431 | * transferred quickly enough! */ | ||
432 | bi.bus_factor = 64; | ||
433 | input_16bit = 0; | ||
434 | break; | ||
435 | default: | ||
436 | result = -EINVAL; | ||
437 | goto out_unlock; | ||
438 | } | ||
439 | /* we assume all sysclocks are the same! */ | ||
440 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
441 | bi.sysclock_factor = cii->codec->sysclock_factor; | ||
442 | break; | ||
443 | } | ||
444 | |||
445 | if (clock_and_divisors(bi.sysclock_factor, | ||
446 | bi.bus_factor, | ||
447 | runtime->rate, | ||
448 | &sfr) < 0) { | ||
449 | result = -EINVAL; | ||
450 | goto out_unlock; | ||
451 | } | ||
452 | switch (bi.bus_factor) { | ||
453 | case 32: | ||
454 | sfr |= I2S_SF_SERIAL_FORMAT_I2S_32X; | ||
455 | break; | ||
456 | case 64: | ||
457 | sfr |= I2S_SF_SERIAL_FORMAT_I2S_64X; | ||
458 | break; | ||
459 | } | ||
460 | /* FIXME: THIS ASSUMES MASTER ALL THE TIME */ | ||
461 | sfr |= I2S_SF_SCLK_MASTER; | ||
462 | |||
463 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) { | ||
464 | int err = 0; | ||
465 | if (cii->codec->prepare) | ||
466 | err = cii->codec->prepare(cii, &bi, pi->substream); | ||
467 | if (err) { | ||
468 | result = err; | ||
469 | goto out_unlock; | ||
470 | } | ||
471 | } | ||
472 | /* codecs are fine with it, so set our clocks */ | ||
473 | if (input_16bit) | ||
474 | dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) | | ||
475 | (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) | | ||
476 | I2S_DWS_DATA_IN_16BIT | I2S_DWS_DATA_OUT_16BIT; | ||
477 | else | ||
478 | dws = (2 << I2S_DWS_NUM_CHANNELS_IN_SHIFT) | | ||
479 | (2 << I2S_DWS_NUM_CHANNELS_OUT_SHIFT) | | ||
480 | I2S_DWS_DATA_IN_24BIT | I2S_DWS_DATA_OUT_24BIT; | ||
481 | |||
482 | /* early exit if already programmed correctly */ | ||
483 | /* not locking these is fine since we touch them only in this function */ | ||
484 | if (in_le32(&i2sdev->intfregs->serial_format) == sfr | ||
485 | && in_le32(&i2sdev->intfregs->data_word_sizes) == dws) | ||
486 | goto out_unlock; | ||
487 | |||
488 | /* let's notify the codecs about clocks going away. | ||
489 | * For now we only do mastering on the i2s cell... */ | ||
490 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
491 | if (cii->codec->switch_clock) | ||
492 | cii->codec->switch_clock(cii, CLOCK_SWITCH_PREPARE_SLAVE); | ||
493 | |||
494 | i2sbus_control_enable(i2sdev->control, i2sdev); | ||
495 | i2sbus_control_cell(i2sdev->control, i2sdev, 1); | ||
496 | |||
497 | out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED); | ||
498 | |||
499 | i2sbus_control_clock(i2sdev->control, i2sdev, 0); | ||
500 | |||
501 | msleep(1); | ||
502 | |||
503 | /* wait for clock stopped. This can apparently take a while... */ | ||
504 | cnt = 100; | ||
505 | while (cnt-- && | ||
506 | !(in_le32(&i2sdev->intfregs->intr_ctl) & I2S_PENDING_CLOCKS_STOPPED)) { | ||
507 | msleep(5); | ||
508 | } | ||
509 | out_le32(&i2sdev->intfregs->intr_ctl, I2S_PENDING_CLOCKS_STOPPED); | ||
510 | |||
511 | /* not locking these is fine since we touch them only in this function */ | ||
512 | out_le32(&i2sdev->intfregs->serial_format, sfr); | ||
513 | out_le32(&i2sdev->intfregs->data_word_sizes, dws); | ||
514 | |||
515 | i2sbus_control_enable(i2sdev->control, i2sdev); | ||
516 | i2sbus_control_cell(i2sdev->control, i2sdev, 1); | ||
517 | i2sbus_control_clock(i2sdev->control, i2sdev, 1); | ||
518 | msleep(1); | ||
519 | |||
520 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
521 | if (cii->codec->switch_clock) | ||
522 | cii->codec->switch_clock(cii, CLOCK_SWITCH_SLAVE); | ||
523 | |||
524 | out_unlock: | ||
525 | mutex_unlock(&i2sdev->lock); | ||
526 | return result; | ||
527 | } | ||
528 | |||
529 | #ifdef CONFIG_PM | ||
530 | void i2sbus_pcm_prepare_both(struct i2sbus_dev *i2sdev) | ||
531 | { | ||
532 | i2sbus_pcm_prepare(i2sdev, 0); | ||
533 | i2sbus_pcm_prepare(i2sdev, 1); | ||
534 | } | ||
535 | #endif | ||
536 | |||
537 | static int i2sbus_pcm_trigger(struct i2sbus_dev *i2sdev, int in, int cmd) | ||
538 | { | ||
539 | struct codec_info_item *cii; | ||
540 | struct pcm_info *pi; | ||
541 | int result = 0; | ||
542 | unsigned long flags; | ||
543 | |||
544 | spin_lock_irqsave(&i2sdev->low_lock, flags); | ||
545 | |||
546 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
547 | |||
548 | switch (cmd) { | ||
549 | case SNDRV_PCM_TRIGGER_START: | ||
550 | case SNDRV_PCM_TRIGGER_RESUME: | ||
551 | if (pi->dbdma_ring.running) { | ||
552 | result = -EALREADY; | ||
553 | goto out_unlock; | ||
554 | } | ||
555 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
556 | if (cii->codec->start) | ||
557 | cii->codec->start(cii, pi->substream); | ||
558 | pi->dbdma_ring.running = 1; | ||
559 | |||
560 | if (pi->dbdma_ring.stopping) { | ||
561 | /* Clear the S0 bit, then see if we stopped yet */ | ||
562 | out_le32(&pi->dbdma->control, 1 << 16); | ||
563 | if (in_le32(&pi->dbdma->status) & ACTIVE) { | ||
564 | /* possible race here? */ | ||
565 | udelay(10); | ||
566 | if (in_le32(&pi->dbdma->status) & ACTIVE) { | ||
567 | pi->dbdma_ring.stopping = 0; | ||
568 | goto out_unlock; /* keep running */ | ||
569 | } | ||
570 | } | ||
571 | } | ||
572 | |||
573 | /* make sure RUN, PAUSE and S0 bits are cleared */ | ||
574 | out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); | ||
575 | |||
576 | /* set branch condition select register */ | ||
577 | out_le32(&pi->dbdma->br_sel, (1 << 16) | 1); | ||
578 | |||
579 | /* write dma command buffer address to the dbdma chip */ | ||
580 | out_le32(&pi->dbdma->cmdptr, pi->dbdma_ring.bus_cmd_start); | ||
581 | |||
582 | /* initialize the frame count and current period */ | ||
583 | pi->current_period = 0; | ||
584 | pi->frame_count = in_le32(&i2sdev->intfregs->frame_count); | ||
585 | |||
586 | /* set the DMA controller running */ | ||
587 | out_le32(&pi->dbdma->control, (RUN << 16) | RUN); | ||
588 | |||
589 | /* off you go! */ | ||
590 | break; | ||
591 | |||
592 | case SNDRV_PCM_TRIGGER_STOP: | ||
593 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
594 | if (!pi->dbdma_ring.running) { | ||
595 | result = -EALREADY; | ||
596 | goto out_unlock; | ||
597 | } | ||
598 | pi->dbdma_ring.running = 0; | ||
599 | |||
600 | /* Set the S0 bit to make the DMA branch to the stop cmd */ | ||
601 | out_le32(&pi->dbdma->control, (1 << 16) | 1); | ||
602 | pi->dbdma_ring.stopping = 1; | ||
603 | |||
604 | list_for_each_entry(cii, &i2sdev->sound.codec_list, list) | ||
605 | if (cii->codec->stop) | ||
606 | cii->codec->stop(cii, pi->substream); | ||
607 | break; | ||
608 | default: | ||
609 | result = -EINVAL; | ||
610 | goto out_unlock; | ||
611 | } | ||
612 | |||
613 | out_unlock: | ||
614 | spin_unlock_irqrestore(&i2sdev->low_lock, flags); | ||
615 | return result; | ||
616 | } | ||
617 | |||
618 | static snd_pcm_uframes_t i2sbus_pcm_pointer(struct i2sbus_dev *i2sdev, int in) | ||
619 | { | ||
620 | struct pcm_info *pi; | ||
621 | u32 fc; | ||
622 | |||
623 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
624 | |||
625 | fc = in_le32(&i2sdev->intfregs->frame_count); | ||
626 | fc = fc - pi->frame_count; | ||
627 | |||
628 | if (fc >= pi->substream->runtime->buffer_size) | ||
629 | fc %= pi->substream->runtime->buffer_size; | ||
630 | return fc; | ||
631 | } | ||
632 | |||
633 | static inline void handle_interrupt(struct i2sbus_dev *i2sdev, int in) | ||
634 | { | ||
635 | struct pcm_info *pi; | ||
636 | u32 fc, nframes; | ||
637 | u32 status; | ||
638 | int timeout, i; | ||
639 | int dma_stopped = 0; | ||
640 | struct snd_pcm_runtime *runtime; | ||
641 | |||
642 | spin_lock(&i2sdev->low_lock); | ||
643 | get_pcm_info(i2sdev, in, &pi, NULL); | ||
644 | if (!pi->dbdma_ring.running && !pi->dbdma_ring.stopping) | ||
645 | goto out_unlock; | ||
646 | |||
647 | i = pi->current_period; | ||
648 | runtime = pi->substream->runtime; | ||
649 | while (pi->dbdma_ring.cmds[i].xfer_status) { | ||
650 | if (le16_to_cpu(pi->dbdma_ring.cmds[i].xfer_status) & BT) | ||
651 | /* | ||
652 | * BT is the branch taken bit. If it took a branch | ||
653 | * it is because we set the S0 bit to make it | ||
654 | * branch to the stop command. | ||
655 | */ | ||
656 | dma_stopped = 1; | ||
657 | pi->dbdma_ring.cmds[i].xfer_status = 0; | ||
658 | |||
659 | if (++i >= runtime->periods) { | ||
660 | i = 0; | ||
661 | pi->frame_count += runtime->buffer_size; | ||
662 | } | ||
663 | pi->current_period = i; | ||
664 | |||
665 | /* | ||
666 | * Check the frame count. The DMA tends to get a bit | ||
667 | * ahead of the frame counter, which confuses the core. | ||
668 | */ | ||
669 | fc = in_le32(&i2sdev->intfregs->frame_count); | ||
670 | nframes = i * runtime->period_size; | ||
671 | if (fc < pi->frame_count + nframes) | ||
672 | pi->frame_count = fc - nframes; | ||
673 | } | ||
674 | |||
675 | if (dma_stopped) { | ||
676 | timeout = 1000; | ||
677 | for (;;) { | ||
678 | status = in_le32(&pi->dbdma->status); | ||
679 | if (!(status & ACTIVE) && (!in || (status & 0x80))) | ||
680 | break; | ||
681 | if (--timeout <= 0) { | ||
682 | printk(KERN_ERR "i2sbus: timed out " | ||
683 | "waiting for DMA to stop!\n"); | ||
684 | break; | ||
685 | } | ||
686 | udelay(1); | ||
687 | } | ||
688 | |||
689 | /* Turn off DMA controller, clear S0 bit */ | ||
690 | out_le32(&pi->dbdma->control, (RUN | PAUSE | 1) << 16); | ||
691 | |||
692 | pi->dbdma_ring.stopping = 0; | ||
693 | if (pi->stop_completion) | ||
694 | complete(pi->stop_completion); | ||
695 | } | ||
696 | |||
697 | if (!pi->dbdma_ring.running) | ||
698 | goto out_unlock; | ||
699 | spin_unlock(&i2sdev->low_lock); | ||
700 | /* may call _trigger again, hence needs to be unlocked */ | ||
701 | snd_pcm_period_elapsed(pi->substream); | ||
702 | return; | ||
703 | |||
704 | out_unlock: | ||
705 | spin_unlock(&i2sdev->low_lock); | ||
706 | } | ||
707 | |||
708 | irqreturn_t i2sbus_tx_intr(int irq, void *devid) | ||
709 | { | ||
710 | handle_interrupt((struct i2sbus_dev *)devid, 0); | ||
711 | return IRQ_HANDLED; | ||
712 | } | ||
713 | |||
714 | irqreturn_t i2sbus_rx_intr(int irq, void *devid) | ||
715 | { | ||
716 | handle_interrupt((struct i2sbus_dev *)devid, 1); | ||
717 | return IRQ_HANDLED; | ||
718 | } | ||
719 | |||
720 | static int i2sbus_playback_open(struct snd_pcm_substream *substream) | ||
721 | { | ||
722 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
723 | |||
724 | if (!i2sdev) | ||
725 | return -EINVAL; | ||
726 | i2sdev->out.substream = substream; | ||
727 | return i2sbus_pcm_open(i2sdev, 0); | ||
728 | } | ||
729 | |||
730 | static int i2sbus_playback_close(struct snd_pcm_substream *substream) | ||
731 | { | ||
732 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
733 | int err; | ||
734 | |||
735 | if (!i2sdev) | ||
736 | return -EINVAL; | ||
737 | if (i2sdev->out.substream != substream) | ||
738 | return -EINVAL; | ||
739 | err = i2sbus_pcm_close(i2sdev, 0); | ||
740 | if (!err) | ||
741 | i2sdev->out.substream = NULL; | ||
742 | return err; | ||
743 | } | ||
744 | |||
745 | static int i2sbus_playback_prepare(struct snd_pcm_substream *substream) | ||
746 | { | ||
747 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
748 | |||
749 | if (!i2sdev) | ||
750 | return -EINVAL; | ||
751 | if (i2sdev->out.substream != substream) | ||
752 | return -EINVAL; | ||
753 | return i2sbus_pcm_prepare(i2sdev, 0); | ||
754 | } | ||
755 | |||
756 | static int i2sbus_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
757 | { | ||
758 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
759 | |||
760 | if (!i2sdev) | ||
761 | return -EINVAL; | ||
762 | if (i2sdev->out.substream != substream) | ||
763 | return -EINVAL; | ||
764 | return i2sbus_pcm_trigger(i2sdev, 0, cmd); | ||
765 | } | ||
766 | |||
767 | static snd_pcm_uframes_t i2sbus_playback_pointer(struct snd_pcm_substream | ||
768 | *substream) | ||
769 | { | ||
770 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
771 | |||
772 | if (!i2sdev) | ||
773 | return -EINVAL; | ||
774 | if (i2sdev->out.substream != substream) | ||
775 | return 0; | ||
776 | return i2sbus_pcm_pointer(i2sdev, 0); | ||
777 | } | ||
778 | |||
779 | static struct snd_pcm_ops i2sbus_playback_ops = { | ||
780 | .open = i2sbus_playback_open, | ||
781 | .close = i2sbus_playback_close, | ||
782 | .ioctl = snd_pcm_lib_ioctl, | ||
783 | .hw_params = i2sbus_hw_params, | ||
784 | .hw_free = i2sbus_playback_hw_free, | ||
785 | .prepare = i2sbus_playback_prepare, | ||
786 | .trigger = i2sbus_playback_trigger, | ||
787 | .pointer = i2sbus_playback_pointer, | ||
788 | }; | ||
789 | |||
790 | static int i2sbus_record_open(struct snd_pcm_substream *substream) | ||
791 | { | ||
792 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
793 | |||
794 | if (!i2sdev) | ||
795 | return -EINVAL; | ||
796 | i2sdev->in.substream = substream; | ||
797 | return i2sbus_pcm_open(i2sdev, 1); | ||
798 | } | ||
799 | |||
800 | static int i2sbus_record_close(struct snd_pcm_substream *substream) | ||
801 | { | ||
802 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
803 | int err; | ||
804 | |||
805 | if (!i2sdev) | ||
806 | return -EINVAL; | ||
807 | if (i2sdev->in.substream != substream) | ||
808 | return -EINVAL; | ||
809 | err = i2sbus_pcm_close(i2sdev, 1); | ||
810 | if (!err) | ||
811 | i2sdev->in.substream = NULL; | ||
812 | return err; | ||
813 | } | ||
814 | |||
815 | static int i2sbus_record_prepare(struct snd_pcm_substream *substream) | ||
816 | { | ||
817 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
818 | |||
819 | if (!i2sdev) | ||
820 | return -EINVAL; | ||
821 | if (i2sdev->in.substream != substream) | ||
822 | return -EINVAL; | ||
823 | return i2sbus_pcm_prepare(i2sdev, 1); | ||
824 | } | ||
825 | |||
826 | static int i2sbus_record_trigger(struct snd_pcm_substream *substream, int cmd) | ||
827 | { | ||
828 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
829 | |||
830 | if (!i2sdev) | ||
831 | return -EINVAL; | ||
832 | if (i2sdev->in.substream != substream) | ||
833 | return -EINVAL; | ||
834 | return i2sbus_pcm_trigger(i2sdev, 1, cmd); | ||
835 | } | ||
836 | |||
837 | static snd_pcm_uframes_t i2sbus_record_pointer(struct snd_pcm_substream | ||
838 | *substream) | ||
839 | { | ||
840 | struct i2sbus_dev *i2sdev = snd_pcm_substream_chip(substream); | ||
841 | |||
842 | if (!i2sdev) | ||
843 | return -EINVAL; | ||
844 | if (i2sdev->in.substream != substream) | ||
845 | return 0; | ||
846 | return i2sbus_pcm_pointer(i2sdev, 1); | ||
847 | } | ||
848 | |||
849 | static struct snd_pcm_ops i2sbus_record_ops = { | ||
850 | .open = i2sbus_record_open, | ||
851 | .close = i2sbus_record_close, | ||
852 | .ioctl = snd_pcm_lib_ioctl, | ||
853 | .hw_params = i2sbus_hw_params, | ||
854 | .hw_free = i2sbus_record_hw_free, | ||
855 | .prepare = i2sbus_record_prepare, | ||
856 | .trigger = i2sbus_record_trigger, | ||
857 | .pointer = i2sbus_record_pointer, | ||
858 | }; | ||
859 | |||
860 | static void i2sbus_private_free(struct snd_pcm *pcm) | ||
861 | { | ||
862 | struct i2sbus_dev *i2sdev = snd_pcm_chip(pcm); | ||
863 | struct codec_info_item *p, *tmp; | ||
864 | |||
865 | i2sdev->sound.pcm = NULL; | ||
866 | i2sdev->out.created = 0; | ||
867 | i2sdev->in.created = 0; | ||
868 | list_for_each_entry_safe(p, tmp, &i2sdev->sound.codec_list, list) { | ||
869 | printk(KERN_ERR "i2sbus: a codec didn't unregister!\n"); | ||
870 | list_del(&p->list); | ||
871 | module_put(p->codec->owner); | ||
872 | kfree(p); | ||
873 | } | ||
874 | soundbus_dev_put(&i2sdev->sound); | ||
875 | module_put(THIS_MODULE); | ||
876 | } | ||
877 | |||
878 | int | ||
879 | i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card, | ||
880 | struct codec_info *ci, void *data) | ||
881 | { | ||
882 | int err, in = 0, out = 0; | ||
883 | struct transfer_info *tmp; | ||
884 | struct i2sbus_dev *i2sdev = soundbus_dev_to_i2sbus_dev(dev); | ||
885 | struct codec_info_item *cii; | ||
886 | |||
887 | if (!dev->pcmname || dev->pcmid == -1) { | ||
888 | printk(KERN_ERR "i2sbus: pcm name and id must be set!\n"); | ||
889 | return -EINVAL; | ||
890 | } | ||
891 | |||
892 | list_for_each_entry(cii, &dev->codec_list, list) { | ||
893 | if (cii->codec_data == data) | ||
894 | return -EALREADY; | ||
895 | } | ||
896 | |||
897 | if (!ci->transfers || !ci->transfers->formats | ||
898 | || !ci->transfers->rates || !ci->usable) | ||
899 | return -EINVAL; | ||
900 | |||
901 | /* we currently code the i2s transfer on the clock, and support only | ||
902 | * 32 and 64 */ | ||
903 | if (ci->bus_factor != 32 && ci->bus_factor != 64) | ||
904 | return -EINVAL; | ||
905 | |||
906 | /* If you want to fix this, you need to keep track of what transport infos | ||
907 | * are to be used, which codecs they belong to, and then fix all the | ||
908 | * sysclock/busclock stuff above to depend on which is usable */ | ||
909 | list_for_each_entry(cii, &dev->codec_list, list) { | ||
910 | if (cii->codec->sysclock_factor != ci->sysclock_factor) { | ||
911 | printk(KERN_DEBUG | ||
912 | "cannot yet handle multiple different sysclocks!\n"); | ||
913 | return -EINVAL; | ||
914 | } | ||
915 | if (cii->codec->bus_factor != ci->bus_factor) { | ||
916 | printk(KERN_DEBUG | ||
917 | "cannot yet handle multiple different bus clocks!\n"); | ||
918 | return -EINVAL; | ||
919 | } | ||
920 | } | ||
921 | |||
922 | tmp = ci->transfers; | ||
923 | while (tmp->formats && tmp->rates) { | ||
924 | if (tmp->transfer_in) | ||
925 | in = 1; | ||
926 | else | ||
927 | out = 1; | ||
928 | tmp++; | ||
929 | } | ||
930 | |||
931 | cii = kzalloc(sizeof(struct codec_info_item), GFP_KERNEL); | ||
932 | if (!cii) { | ||
933 | printk(KERN_DEBUG "i2sbus: failed to allocate cii\n"); | ||
934 | return -ENOMEM; | ||
935 | } | ||
936 | |||
937 | /* use the private data to point to the codec info */ | ||
938 | cii->sdev = soundbus_dev_get(dev); | ||
939 | cii->codec = ci; | ||
940 | cii->codec_data = data; | ||
941 | |||
942 | if (!cii->sdev) { | ||
943 | printk(KERN_DEBUG | ||
944 | "i2sbus: failed to get soundbus dev reference\n"); | ||
945 | err = -ENODEV; | ||
946 | goto out_free_cii; | ||
947 | } | ||
948 | |||
949 | if (!try_module_get(THIS_MODULE)) { | ||
950 | printk(KERN_DEBUG "i2sbus: failed to get module reference!\n"); | ||
951 | err = -EBUSY; | ||
952 | goto out_put_sdev; | ||
953 | } | ||
954 | |||
955 | if (!try_module_get(ci->owner)) { | ||
956 | printk(KERN_DEBUG | ||
957 | "i2sbus: failed to get module reference to codec owner!\n"); | ||
958 | err = -EBUSY; | ||
959 | goto out_put_this_module; | ||
960 | } | ||
961 | |||
962 | if (!dev->pcm) { | ||
963 | err = snd_pcm_new(card, dev->pcmname, dev->pcmid, 0, 0, | ||
964 | &dev->pcm); | ||
965 | if (err) { | ||
966 | printk(KERN_DEBUG "i2sbus: failed to create pcm\n"); | ||
967 | goto out_put_ci_module; | ||
968 | } | ||
969 | dev->pcm->dev = &dev->ofdev.dev; | ||
970 | } | ||
971 | |||
972 | /* ALSA yet again sucks. | ||
973 | * If it is ever fixed, remove this line. See below. */ | ||
974 | out = in = 1; | ||
975 | |||
976 | if (!i2sdev->out.created && out) { | ||
977 | if (dev->pcm->card != card) { | ||
978 | /* eh? */ | ||
979 | printk(KERN_ERR | ||
980 | "Can't attach same bus to different cards!\n"); | ||
981 | err = -EINVAL; | ||
982 | goto out_put_ci_module; | ||
983 | } | ||
984 | err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, 1); | ||
985 | if (err) | ||
986 | goto out_put_ci_module; | ||
987 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
988 | &i2sbus_playback_ops); | ||
989 | i2sdev->out.created = 1; | ||
990 | } | ||
991 | |||
992 | if (!i2sdev->in.created && in) { | ||
993 | if (dev->pcm->card != card) { | ||
994 | printk(KERN_ERR | ||
995 | "Can't attach same bus to different cards!\n"); | ||
996 | err = -EINVAL; | ||
997 | goto out_put_ci_module; | ||
998 | } | ||
999 | err = snd_pcm_new_stream(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, 1); | ||
1000 | if (err) | ||
1001 | goto out_put_ci_module; | ||
1002 | snd_pcm_set_ops(dev->pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
1003 | &i2sbus_record_ops); | ||
1004 | i2sdev->in.created = 1; | ||
1005 | } | ||
1006 | |||
1007 | /* so we have to register the pcm after adding any substream | ||
1008 | * to it because alsa doesn't create the devices for the | ||
1009 | * substreams when we add them later. | ||
1010 | * Therefore, force in and out on both busses (above) and | ||
1011 | * register the pcm now instead of just after creating it. | ||
1012 | */ | ||
1013 | err = snd_device_register(card, dev->pcm); | ||
1014 | if (err) { | ||
1015 | printk(KERN_ERR "i2sbus: error registering new pcm\n"); | ||
1016 | goto out_put_ci_module; | ||
1017 | } | ||
1018 | /* no errors any more, so let's add this to our list */ | ||
1019 | list_add(&cii->list, &dev->codec_list); | ||
1020 | |||
1021 | dev->pcm->private_data = i2sdev; | ||
1022 | dev->pcm->private_free = i2sbus_private_free; | ||
1023 | |||
1024 | /* well, we really should support scatter/gather DMA */ | ||
1025 | snd_pcm_lib_preallocate_pages_for_all( | ||
1026 | dev->pcm, SNDRV_DMA_TYPE_DEV, | ||
1027 | snd_dma_pci_data(macio_get_pci_dev(i2sdev->macio)), | ||
1028 | 64 * 1024, 64 * 1024); | ||
1029 | |||
1030 | return 0; | ||
1031 | out_put_ci_module: | ||
1032 | module_put(ci->owner); | ||
1033 | out_put_this_module: | ||
1034 | module_put(THIS_MODULE); | ||
1035 | out_put_sdev: | ||
1036 | soundbus_dev_put(dev); | ||
1037 | out_free_cii: | ||
1038 | kfree(cii); | ||
1039 | return err; | ||
1040 | } | ||
1041 | |||
1042 | void i2sbus_detach_codec(struct soundbus_dev *dev, void *data) | ||
1043 | { | ||
1044 | struct codec_info_item *cii = NULL, *i; | ||
1045 | |||
1046 | list_for_each_entry(i, &dev->codec_list, list) { | ||
1047 | if (i->codec_data == data) { | ||
1048 | cii = i; | ||
1049 | break; | ||
1050 | } | ||
1051 | } | ||
1052 | if (cii) { | ||
1053 | list_del(&cii->list); | ||
1054 | module_put(cii->codec->owner); | ||
1055 | kfree(cii); | ||
1056 | } | ||
1057 | /* no more codecs, but still a pcm? */ | ||
1058 | if (list_empty(&dev->codec_list) && dev->pcm) { | ||
1059 | /* the actual cleanup is done by the callback above! */ | ||
1060 | snd_device_free(dev->pcm->card, dev->pcm); | ||
1061 | } | ||
1062 | } | ||