1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * SAA713x ALSA support for V4L |
4 | */ |
5 | |
6 | #include "saa7134.h" |
7 | #include "saa7134-reg.h" |
8 | |
9 | #include <linux/init.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/time.h> |
12 | #include <linux/wait.h> |
13 | #include <linux/module.h> |
14 | #include <sound/core.h> |
15 | #include <sound/control.h> |
16 | #include <sound/pcm.h> |
17 | #include <sound/pcm_params.h> |
18 | #include <sound/initval.h> |
19 | #include <linux/interrupt.h> |
20 | #include <linux/vmalloc.h> |
21 | |
22 | /* |
23 | * Configuration macros |
24 | */ |
25 | |
26 | /* defaults */ |
27 | #define MIXER_ADDR_UNSELECTED -1 |
28 | #define MIXER_ADDR_TVTUNER 0 |
29 | #define MIXER_ADDR_LINE1 1 |
30 | #define MIXER_ADDR_LINE2 2 |
31 | #define MIXER_ADDR_LAST 2 |
32 | |
33 | |
34 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
35 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
36 | static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1}; |
37 | |
38 | module_param_array(index, int, NULL, 0444); |
39 | module_param_array(enable, int, NULL, 0444); |
40 | MODULE_PARM_DESC(index, "Index value for SAA7134 capture interface(s)." ); |
41 | MODULE_PARM_DESC(enable, "Enable (or not) the SAA7134 capture interface(s)." ); |
42 | |
43 | /* |
44 | * Main chip structure |
45 | */ |
46 | |
47 | typedef struct snd_card_saa7134 { |
48 | struct snd_card *card; |
49 | spinlock_t mixer_lock; |
50 | int mixer_volume[MIXER_ADDR_LAST+1][2]; |
51 | int capture_source_addr; |
52 | int capture_source[2]; |
53 | struct snd_kcontrol *capture_ctl[MIXER_ADDR_LAST+1]; |
54 | struct pci_dev *pci; |
55 | struct saa7134_dev *dev; |
56 | |
57 | unsigned long iobase; |
58 | s16 irq; |
59 | u16 mute_was_on; |
60 | |
61 | spinlock_t lock; |
62 | } snd_card_saa7134_t; |
63 | |
64 | |
65 | /* |
66 | * PCM structure |
67 | */ |
68 | |
69 | typedef struct snd_card_saa7134_pcm { |
70 | struct saa7134_dev *dev; |
71 | |
72 | spinlock_t lock; |
73 | |
74 | struct snd_pcm_substream *substream; |
75 | } snd_card_saa7134_pcm_t; |
76 | |
77 | static struct snd_card *snd_saa7134_cards[SNDRV_CARDS]; |
78 | |
79 | |
80 | /* |
81 | * saa7134 DMA audio stop |
82 | * |
83 | * Called when the capture device is released or the buffer overflows |
84 | * |
85 | * - Copied verbatim from saa7134-oss's dsp_dma_stop. |
86 | * |
87 | */ |
88 | |
89 | static void saa7134_dma_stop(struct saa7134_dev *dev) |
90 | { |
91 | dev->dmasound.dma_blk = -1; |
92 | dev->dmasound.dma_running = 0; |
93 | saa7134_set_dmabits(dev); |
94 | } |
95 | |
96 | /* |
97 | * saa7134 DMA audio start |
98 | * |
99 | * Called when preparing the capture device for use |
100 | * |
101 | * - Copied verbatim from saa7134-oss's dsp_dma_start. |
102 | * |
103 | */ |
104 | |
105 | static void saa7134_dma_start(struct saa7134_dev *dev) |
106 | { |
107 | dev->dmasound.dma_blk = 0; |
108 | dev->dmasound.dma_running = 1; |
109 | saa7134_set_dmabits(dev); |
110 | } |
111 | |
112 | /* |
113 | * saa7134 audio DMA IRQ handler |
114 | * |
115 | * Called whenever we get an SAA7134_IRQ_REPORT_DONE_RA3 interrupt |
116 | * Handles shifting between the 2 buffers, manages the read counters, |
117 | * and notifies ALSA when periods elapse |
118 | * |
119 | * - Mostly copied from saa7134-oss's saa7134_irq_oss_done. |
120 | * |
121 | */ |
122 | |
123 | static void saa7134_irq_alsa_done(struct saa7134_dev *dev, |
124 | unsigned long status) |
125 | { |
126 | int next_blk, reg = 0; |
127 | |
128 | spin_lock(lock: &dev->slock); |
129 | if (UNSET == dev->dmasound.dma_blk) { |
130 | pr_debug("irq: recording stopped\n" ); |
131 | goto done; |
132 | } |
133 | if (0 != (status & 0x0f000000)) |
134 | pr_debug("irq: lost %ld\n" , (status >> 24) & 0x0f); |
135 | if (0 == (status & 0x10000000)) { |
136 | /* odd */ |
137 | if (0 == (dev->dmasound.dma_blk & 0x01)) |
138 | reg = SAA7134_RS_BA1(6); |
139 | } else { |
140 | /* even */ |
141 | if (1 == (dev->dmasound.dma_blk & 0x01)) |
142 | reg = SAA7134_RS_BA2(6); |
143 | } |
144 | if (0 == reg) { |
145 | pr_debug("irq: field oops [%s]\n" , |
146 | (status & 0x10000000) ? "even" : "odd" ); |
147 | goto done; |
148 | } |
149 | |
150 | if (dev->dmasound.read_count >= dev->dmasound.blksize * (dev->dmasound.blocks-2)) { |
151 | pr_debug("irq: overrun [full=%d/%d] - Blocks in %d\n" , |
152 | dev->dmasound.read_count, |
153 | dev->dmasound.bufsize, dev->dmasound.blocks); |
154 | spin_unlock(lock: &dev->slock); |
155 | snd_pcm_stop_xrun(substream: dev->dmasound.substream); |
156 | return; |
157 | } |
158 | |
159 | /* next block addr */ |
160 | next_blk = (dev->dmasound.dma_blk + 2) % dev->dmasound.blocks; |
161 | saa_writel(reg,next_blk * dev->dmasound.blksize); |
162 | pr_debug("irq: ok, %s, next_blk=%d, addr=%x, blocks=%u, size=%u, read=%u\n" , |
163 | (status & 0x10000000) ? "even" : "odd " , next_blk, |
164 | next_blk * dev->dmasound.blksize, dev->dmasound.blocks, |
165 | dev->dmasound.blksize, dev->dmasound.read_count); |
166 | |
167 | /* update status & wake waiting readers */ |
168 | dev->dmasound.dma_blk = (dev->dmasound.dma_blk + 1) % dev->dmasound.blocks; |
169 | dev->dmasound.read_count += dev->dmasound.blksize; |
170 | |
171 | dev->dmasound.recording_on = reg; |
172 | |
173 | if (dev->dmasound.read_count >= snd_pcm_lib_period_bytes(substream: dev->dmasound.substream)) { |
174 | spin_unlock(lock: &dev->slock); |
175 | snd_pcm_period_elapsed(substream: dev->dmasound.substream); |
176 | spin_lock(lock: &dev->slock); |
177 | } |
178 | |
179 | done: |
180 | spin_unlock(lock: &dev->slock); |
181 | |
182 | } |
183 | |
184 | /* |
185 | * IRQ request handler |
186 | * |
187 | * Runs along with saa7134's IRQ handler, discards anything that isn't |
188 | * DMA sound |
189 | * |
190 | */ |
191 | |
192 | static irqreturn_t saa7134_alsa_irq(int irq, void *dev_id) |
193 | { |
194 | struct saa7134_dmasound *dmasound = dev_id; |
195 | struct saa7134_dev *dev = dmasound->priv_data; |
196 | |
197 | unsigned long report, status; |
198 | int loop, handled = 0; |
199 | |
200 | for (loop = 0; loop < 10; loop++) { |
201 | report = saa_readl(SAA7134_IRQ_REPORT); |
202 | status = saa_readl(SAA7134_IRQ_STATUS); |
203 | |
204 | if (report & SAA7134_IRQ_REPORT_DONE_RA3) { |
205 | handled = 1; |
206 | saa_writel(SAA7134_IRQ_REPORT, |
207 | SAA7134_IRQ_REPORT_DONE_RA3); |
208 | saa7134_irq_alsa_done(dev, status); |
209 | } else { |
210 | goto out; |
211 | } |
212 | } |
213 | |
214 | if (loop == 10) { |
215 | pr_debug("error! looping IRQ!" ); |
216 | } |
217 | |
218 | out: |
219 | return IRQ_RETVAL(handled); |
220 | } |
221 | |
222 | /* |
223 | * ALSA capture trigger |
224 | * |
225 | * - One of the ALSA capture callbacks. |
226 | * |
227 | * Called whenever a capture is started or stopped. Must be defined, |
228 | * but there's nothing we want to do here |
229 | * |
230 | */ |
231 | |
232 | static int snd_card_saa7134_capture_trigger(struct snd_pcm_substream * substream, |
233 | int cmd) |
234 | { |
235 | struct snd_pcm_runtime *runtime = substream->runtime; |
236 | snd_card_saa7134_pcm_t *pcm = runtime->private_data; |
237 | struct saa7134_dev *dev=pcm->dev; |
238 | int err = 0; |
239 | |
240 | spin_lock(lock: &dev->slock); |
241 | if (cmd == SNDRV_PCM_TRIGGER_START) { |
242 | /* start dma */ |
243 | saa7134_dma_start(dev); |
244 | } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { |
245 | /* stop dma */ |
246 | saa7134_dma_stop(dev); |
247 | } else { |
248 | err = -EINVAL; |
249 | } |
250 | spin_unlock(lock: &dev->slock); |
251 | |
252 | return err; |
253 | } |
254 | |
255 | static int saa7134_alsa_dma_init(struct saa7134_dev *dev, |
256 | unsigned long nr_pages) |
257 | { |
258 | struct saa7134_dmasound *dma = &dev->dmasound; |
259 | struct page *pg; |
260 | int i; |
261 | |
262 | dma->vaddr = vmalloc_32(size: nr_pages << PAGE_SHIFT); |
263 | if (NULL == dma->vaddr) { |
264 | pr_debug("vmalloc_32(%lu pages) failed\n" , nr_pages); |
265 | return -ENOMEM; |
266 | } |
267 | |
268 | pr_debug("vmalloc is at addr %p, size=%lu\n" , |
269 | dma->vaddr, nr_pages << PAGE_SHIFT); |
270 | |
271 | memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT); |
272 | dma->nr_pages = nr_pages; |
273 | |
274 | dma->sglist = vzalloc(array_size(sizeof(*dma->sglist), dma->nr_pages)); |
275 | if (NULL == dma->sglist) |
276 | goto vzalloc_err; |
277 | |
278 | sg_init_table(dma->sglist, dma->nr_pages); |
279 | for (i = 0; i < dma->nr_pages; i++) { |
280 | pg = vmalloc_to_page(addr: dma->vaddr + i * PAGE_SIZE); |
281 | if (NULL == pg) |
282 | goto vmalloc_to_page_err; |
283 | sg_set_page(sg: &dma->sglist[i], page: pg, PAGE_SIZE, offset: 0); |
284 | } |
285 | return 0; |
286 | |
287 | vmalloc_to_page_err: |
288 | vfree(addr: dma->sglist); |
289 | dma->sglist = NULL; |
290 | vzalloc_err: |
291 | vfree(addr: dma->vaddr); |
292 | dma->vaddr = NULL; |
293 | return -ENOMEM; |
294 | } |
295 | |
296 | static int saa7134_alsa_dma_map(struct saa7134_dev *dev) |
297 | { |
298 | struct saa7134_dmasound *dma = &dev->dmasound; |
299 | |
300 | dma->sglen = dma_map_sg(&dev->pci->dev, dma->sglist, |
301 | dma->nr_pages, DMA_FROM_DEVICE); |
302 | |
303 | if (0 == dma->sglen) { |
304 | pr_warn("%s: saa7134_alsa_map_sg failed\n" , __func__); |
305 | return -ENOMEM; |
306 | } |
307 | return 0; |
308 | } |
309 | |
310 | static int saa7134_alsa_dma_unmap(struct saa7134_dev *dev) |
311 | { |
312 | struct saa7134_dmasound *dma = &dev->dmasound; |
313 | |
314 | if (!dma->sglen) |
315 | return 0; |
316 | |
317 | dma_unmap_sg(&dev->pci->dev, dma->sglist, dma->nr_pages, DMA_FROM_DEVICE); |
318 | dma->sglen = 0; |
319 | return 0; |
320 | } |
321 | |
322 | static int saa7134_alsa_dma_free(struct saa7134_dmasound *dma) |
323 | { |
324 | vfree(addr: dma->sglist); |
325 | dma->sglist = NULL; |
326 | vfree(addr: dma->vaddr); |
327 | dma->vaddr = NULL; |
328 | return 0; |
329 | } |
330 | |
331 | /* |
332 | * DMA buffer initialization |
333 | * |
334 | * Uses V4L functions to initialize the DMA. Shouldn't be necessary in |
335 | * ALSA, but I was unable to use ALSA's own DMA, and had to force the |
336 | * usage of V4L's |
337 | * |
338 | * - Copied verbatim from saa7134-oss. |
339 | * |
340 | */ |
341 | |
342 | static int dsp_buffer_init(struct saa7134_dev *dev) |
343 | { |
344 | int err; |
345 | |
346 | BUG_ON(!dev->dmasound.bufsize); |
347 | |
348 | err = saa7134_alsa_dma_init(dev, |
349 | nr_pages: (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT); |
350 | if (0 != err) |
351 | return err; |
352 | return 0; |
353 | } |
354 | |
355 | /* |
356 | * DMA buffer release |
357 | * |
358 | * Called after closing the device, during snd_card_saa7134_capture_close |
359 | * |
360 | */ |
361 | |
362 | static int dsp_buffer_free(struct saa7134_dev *dev) |
363 | { |
364 | BUG_ON(!dev->dmasound.blksize); |
365 | |
366 | saa7134_alsa_dma_free(dma: &dev->dmasound); |
367 | |
368 | dev->dmasound.blocks = 0; |
369 | dev->dmasound.blksize = 0; |
370 | dev->dmasound.bufsize = 0; |
371 | |
372 | return 0; |
373 | } |
374 | |
375 | /* |
376 | * Setting the capture source and updating the ALSA controls |
377 | */ |
378 | static int snd_saa7134_capsrc_set(struct snd_kcontrol *kcontrol, |
379 | int left, int right, bool force_notify) |
380 | { |
381 | snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); |
382 | int change = 0, addr = kcontrol->private_value; |
383 | int active, old_addr; |
384 | u32 anabar, xbarin; |
385 | int analog_io, rate; |
386 | struct saa7134_dev *dev; |
387 | |
388 | dev = chip->dev; |
389 | |
390 | spin_lock_irq(lock: &chip->mixer_lock); |
391 | |
392 | active = left != 0 || right != 0; |
393 | old_addr = chip->capture_source_addr; |
394 | |
395 | /* The active capture source cannot be deactivated */ |
396 | if (active) { |
397 | change = old_addr != addr || |
398 | chip->capture_source[0] != left || |
399 | chip->capture_source[1] != right; |
400 | |
401 | chip->capture_source[0] = left; |
402 | chip->capture_source[1] = right; |
403 | chip->capture_source_addr = addr; |
404 | dev->dmasound.input = addr; |
405 | } |
406 | spin_unlock_irq(lock: &chip->mixer_lock); |
407 | |
408 | if (change) { |
409 | switch (dev->pci->device) { |
410 | |
411 | case PCI_DEVICE_ID_PHILIPS_SAA7134: |
412 | switch (addr) { |
413 | case MIXER_ADDR_TVTUNER: |
414 | saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, |
415 | 0xc0, 0xc0); |
416 | saa_andorb(SAA7134_SIF_SAMPLE_FREQ, |
417 | 0x03, 0x00); |
418 | break; |
419 | case MIXER_ADDR_LINE1: |
420 | case MIXER_ADDR_LINE2: |
421 | analog_io = (MIXER_ADDR_LINE1 == addr) ? |
422 | 0x00 : 0x08; |
423 | rate = (32000 == dev->dmasound.rate) ? |
424 | 0x01 : 0x03; |
425 | saa_andorb(SAA7134_ANALOG_IO_SELECT, |
426 | 0x08, analog_io); |
427 | saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, |
428 | 0xc0, 0x80); |
429 | saa_andorb(SAA7134_SIF_SAMPLE_FREQ, |
430 | 0x03, rate); |
431 | break; |
432 | } |
433 | |
434 | break; |
435 | case PCI_DEVICE_ID_PHILIPS_SAA7133: |
436 | case PCI_DEVICE_ID_PHILIPS_SAA7135: |
437 | xbarin = 0x03; /* adc */ |
438 | anabar = 0; |
439 | switch (addr) { |
440 | case MIXER_ADDR_TVTUNER: |
441 | xbarin = 0; /* Demodulator */ |
442 | anabar = 2; /* DACs */ |
443 | break; |
444 | case MIXER_ADDR_LINE1: |
445 | anabar = 0; /* aux1, aux1 */ |
446 | break; |
447 | case MIXER_ADDR_LINE2: |
448 | anabar = 9; /* aux2, aux2 */ |
449 | break; |
450 | } |
451 | |
452 | /* output xbar always main channel */ |
453 | saa_dsp_writel(dev, SAA7133_DIGITAL_OUTPUT_SEL1, |
454 | value: 0xbbbb10); |
455 | |
456 | if (left || right) { |
457 | /* We've got data, turn the input on */ |
458 | saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, |
459 | value: xbarin); |
460 | saa_writel(SAA7133_ANALOG_IO_SELECT, anabar); |
461 | } else { |
462 | saa_dsp_writel(dev, SAA7133_DIGITAL_INPUT_XBAR1, |
463 | value: 0); |
464 | saa_writel(SAA7133_ANALOG_IO_SELECT, 0); |
465 | } |
466 | break; |
467 | } |
468 | } |
469 | |
470 | if (change) { |
471 | if (force_notify) |
472 | snd_ctl_notify(card: chip->card, |
473 | SNDRV_CTL_EVENT_MASK_VALUE, |
474 | id: &chip->capture_ctl[addr]->id); |
475 | |
476 | if (old_addr != MIXER_ADDR_UNSELECTED && old_addr != addr) |
477 | snd_ctl_notify(card: chip->card, |
478 | SNDRV_CTL_EVENT_MASK_VALUE, |
479 | id: &chip->capture_ctl[old_addr]->id); |
480 | } |
481 | |
482 | return change; |
483 | } |
484 | |
485 | /* |
486 | * ALSA PCM preparation |
487 | * |
488 | * - One of the ALSA capture callbacks. |
489 | * |
490 | * Called right after the capture device is opened, this function configures |
491 | * the buffer using the previously defined functions, allocates the memory, |
492 | * sets up the hardware registers, and then starts the DMA. When this function |
493 | * returns, the audio should be flowing. |
494 | * |
495 | */ |
496 | |
497 | static int snd_card_saa7134_capture_prepare(struct snd_pcm_substream * substream) |
498 | { |
499 | struct snd_pcm_runtime *runtime = substream->runtime; |
500 | int bswap, sign; |
501 | u32 fmt, control; |
502 | snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); |
503 | struct saa7134_dev *dev; |
504 | snd_card_saa7134_pcm_t *pcm = runtime->private_data; |
505 | |
506 | pcm->dev->dmasound.substream = substream; |
507 | |
508 | dev = saa7134->dev; |
509 | |
510 | if (snd_pcm_format_width(format: runtime->format) == 8) |
511 | fmt = 0x00; |
512 | else |
513 | fmt = 0x01; |
514 | |
515 | if (snd_pcm_format_signed(format: runtime->format)) |
516 | sign = 1; |
517 | else |
518 | sign = 0; |
519 | |
520 | if (snd_pcm_format_big_endian(format: runtime->format)) |
521 | bswap = 1; |
522 | else |
523 | bswap = 0; |
524 | |
525 | switch (dev->pci->device) { |
526 | case PCI_DEVICE_ID_PHILIPS_SAA7134: |
527 | if (1 == runtime->channels) |
528 | fmt |= (1 << 3); |
529 | if (2 == runtime->channels) |
530 | fmt |= (3 << 3); |
531 | if (sign) |
532 | fmt |= 0x04; |
533 | |
534 | fmt |= (MIXER_ADDR_TVTUNER == dev->dmasound.input) ? 0xc0 : 0x80; |
535 | saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->dmasound.blksize - 1) & 0x0000ff)); |
536 | saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->dmasound.blksize - 1) & 0x00ff00) >> 8); |
537 | saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->dmasound.blksize - 1) & 0xff0000) >> 16); |
538 | saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt); |
539 | |
540 | break; |
541 | case PCI_DEVICE_ID_PHILIPS_SAA7133: |
542 | case PCI_DEVICE_ID_PHILIPS_SAA7135: |
543 | if (1 == runtime->channels) |
544 | fmt |= (1 << 4); |
545 | if (2 == runtime->channels) |
546 | fmt |= (2 << 4); |
547 | if (!sign) |
548 | fmt |= 0x04; |
549 | saa_writel(SAA7133_NUM_SAMPLES, dev->dmasound.blksize -1); |
550 | saa_writel(SAA7133_AUDIO_CHANNEL, 0x543210 | (fmt << 24)); |
551 | break; |
552 | } |
553 | |
554 | pr_debug("rec_start: afmt=%d ch=%d => fmt=0x%x swap=%c\n" , |
555 | runtime->format, runtime->channels, fmt, |
556 | bswap ? 'b' : '-'); |
557 | /* dma: setup channel 6 (= AUDIO) */ |
558 | control = SAA7134_RS_CONTROL_BURST_16 | |
559 | SAA7134_RS_CONTROL_ME | |
560 | (dev->dmasound.pt.dma >> 12); |
561 | if (bswap) |
562 | control |= SAA7134_RS_CONTROL_BSWAP; |
563 | |
564 | saa_writel(SAA7134_RS_BA1(6),0); |
565 | saa_writel(SAA7134_RS_BA2(6),dev->dmasound.blksize); |
566 | saa_writel(SAA7134_RS_PITCH(6),0); |
567 | saa_writel(SAA7134_RS_CONTROL(6),control); |
568 | |
569 | dev->dmasound.rate = runtime->rate; |
570 | |
571 | /* Setup and update the card/ALSA controls */ |
572 | snd_saa7134_capsrc_set(kcontrol: saa7134->capture_ctl[dev->dmasound.input], left: 1, right: 1, |
573 | force_notify: true); |
574 | |
575 | return 0; |
576 | |
577 | } |
578 | |
579 | /* |
580 | * ALSA pointer fetching |
581 | * |
582 | * - One of the ALSA capture callbacks. |
583 | * |
584 | * Called whenever a period elapses, it must return the current hardware |
585 | * position of the buffer. |
586 | * Also resets the read counter used to prevent overruns |
587 | * |
588 | */ |
589 | |
590 | static snd_pcm_uframes_t |
591 | snd_card_saa7134_capture_pointer(struct snd_pcm_substream * substream) |
592 | { |
593 | struct snd_pcm_runtime *runtime = substream->runtime; |
594 | snd_card_saa7134_pcm_t *pcm = runtime->private_data; |
595 | struct saa7134_dev *dev=pcm->dev; |
596 | |
597 | if (dev->dmasound.read_count) { |
598 | dev->dmasound.read_count -= snd_pcm_lib_period_bytes(substream); |
599 | dev->dmasound.read_offset += snd_pcm_lib_period_bytes(substream); |
600 | if (dev->dmasound.read_offset == dev->dmasound.bufsize) |
601 | dev->dmasound.read_offset = 0; |
602 | } |
603 | |
604 | return bytes_to_frames(runtime, size: dev->dmasound.read_offset); |
605 | } |
606 | |
607 | /* |
608 | * ALSA hardware capabilities definition |
609 | * |
610 | * Report only 32kHz for ALSA: |
611 | * |
612 | * - SAA7133/35 uses DDEP (DemDec Easy Programming mode), which works in 32kHz |
613 | * only |
614 | * - SAA7134 for TV mode uses DemDec mode (32kHz) |
615 | * - Radio works in 32kHz only |
616 | * - When recording 48kHz from Line1/Line2, switching of capture source to TV |
617 | * means |
618 | * switching to 32kHz without any frequency translation |
619 | */ |
620 | |
621 | static const struct snd_pcm_hardware snd_card_saa7134_capture = |
622 | { |
623 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
624 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
625 | SNDRV_PCM_INFO_MMAP_VALID), |
626 | .formats = SNDRV_PCM_FMTBIT_S16_LE | \ |
627 | SNDRV_PCM_FMTBIT_S16_BE | \ |
628 | SNDRV_PCM_FMTBIT_S8 | \ |
629 | SNDRV_PCM_FMTBIT_U8 | \ |
630 | SNDRV_PCM_FMTBIT_U16_LE | \ |
631 | SNDRV_PCM_FMTBIT_U16_BE, |
632 | .rates = SNDRV_PCM_RATE_32000, |
633 | .rate_min = 32000, |
634 | .rate_max = 32000, |
635 | .channels_min = 1, |
636 | .channels_max = 2, |
637 | .buffer_bytes_max = (256*1024), |
638 | .period_bytes_min = 64, |
639 | .period_bytes_max = (256*1024), |
640 | .periods_min = 4, |
641 | .periods_max = 1024, |
642 | }; |
643 | |
644 | static void snd_card_saa7134_runtime_free(struct snd_pcm_runtime *runtime) |
645 | { |
646 | snd_card_saa7134_pcm_t *pcm = runtime->private_data; |
647 | |
648 | kfree(objp: pcm); |
649 | } |
650 | |
651 | |
652 | /* |
653 | * ALSA hardware params |
654 | * |
655 | * - One of the ALSA capture callbacks. |
656 | * |
657 | * Called on initialization, right before the PCM preparation |
658 | * |
659 | */ |
660 | |
661 | static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream, |
662 | struct snd_pcm_hw_params * hw_params) |
663 | { |
664 | snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); |
665 | struct saa7134_dev *dev; |
666 | unsigned int period_size, periods; |
667 | int err; |
668 | |
669 | period_size = params_period_bytes(p: hw_params); |
670 | periods = params_periods(p: hw_params); |
671 | |
672 | if (period_size < 0x100 || period_size > 0x10000) |
673 | return -EINVAL; |
674 | if (periods < 4) |
675 | return -EINVAL; |
676 | if (period_size * periods > 1024 * 1024) |
677 | return -EINVAL; |
678 | |
679 | dev = saa7134->dev; |
680 | |
681 | if (dev->dmasound.blocks == periods && |
682 | dev->dmasound.blksize == period_size) |
683 | return 0; |
684 | |
685 | /* release the old buffer */ |
686 | if (substream->runtime->dma_area) { |
687 | saa7134_pgtable_free(pci: dev->pci, pt: &dev->dmasound.pt); |
688 | saa7134_alsa_dma_unmap(dev); |
689 | dsp_buffer_free(dev); |
690 | substream->runtime->dma_area = NULL; |
691 | } |
692 | dev->dmasound.blocks = periods; |
693 | dev->dmasound.blksize = period_size; |
694 | dev->dmasound.bufsize = period_size * periods; |
695 | |
696 | err = dsp_buffer_init(dev); |
697 | if (0 != err) { |
698 | dev->dmasound.blocks = 0; |
699 | dev->dmasound.blksize = 0; |
700 | dev->dmasound.bufsize = 0; |
701 | return err; |
702 | } |
703 | |
704 | err = saa7134_alsa_dma_map(dev); |
705 | if (err) { |
706 | dsp_buffer_free(dev); |
707 | return err; |
708 | } |
709 | err = saa7134_pgtable_alloc(pci: dev->pci, pt: &dev->dmasound.pt); |
710 | if (err) { |
711 | saa7134_alsa_dma_unmap(dev); |
712 | dsp_buffer_free(dev); |
713 | return err; |
714 | } |
715 | err = saa7134_pgtable_build(pci: dev->pci, pt: &dev->dmasound.pt, |
716 | list: dev->dmasound.sglist, length: dev->dmasound.sglen, startpage: 0); |
717 | if (err) { |
718 | saa7134_pgtable_free(pci: dev->pci, pt: &dev->dmasound.pt); |
719 | saa7134_alsa_dma_unmap(dev); |
720 | dsp_buffer_free(dev); |
721 | return err; |
722 | } |
723 | |
724 | /* I should be able to use runtime->dma_addr in the control |
725 | byte, but it doesn't work. So I allocate the DMA using the |
726 | V4L functions, and force ALSA to use that as the DMA area */ |
727 | |
728 | substream->runtime->dma_area = dev->dmasound.vaddr; |
729 | substream->runtime->dma_bytes = dev->dmasound.bufsize; |
730 | substream->runtime->dma_addr = 0; |
731 | |
732 | return 0; |
733 | |
734 | } |
735 | |
736 | /* |
737 | * ALSA hardware release |
738 | * |
739 | * - One of the ALSA capture callbacks. |
740 | * |
741 | * Called after closing the device, but before snd_card_saa7134_capture_close |
742 | * It stops the DMA audio and releases the buffers. |
743 | * |
744 | */ |
745 | |
746 | static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream) |
747 | { |
748 | snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); |
749 | struct saa7134_dev *dev; |
750 | |
751 | dev = saa7134->dev; |
752 | |
753 | if (substream->runtime->dma_area) { |
754 | saa7134_pgtable_free(pci: dev->pci, pt: &dev->dmasound.pt); |
755 | saa7134_alsa_dma_unmap(dev); |
756 | dsp_buffer_free(dev); |
757 | substream->runtime->dma_area = NULL; |
758 | } |
759 | |
760 | return 0; |
761 | } |
762 | |
763 | /* |
764 | * ALSA capture finish |
765 | * |
766 | * - One of the ALSA capture callbacks. |
767 | * |
768 | * Called after closing the device. |
769 | * |
770 | */ |
771 | |
772 | static int snd_card_saa7134_capture_close(struct snd_pcm_substream * substream) |
773 | { |
774 | snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); |
775 | struct saa7134_dev *dev = saa7134->dev; |
776 | |
777 | if (saa7134->mute_was_on) { |
778 | dev->ctl_mute = 1; |
779 | saa7134_tvaudio_setmute(dev); |
780 | } |
781 | return 0; |
782 | } |
783 | |
784 | /* |
785 | * ALSA capture start |
786 | * |
787 | * - One of the ALSA capture callbacks. |
788 | * |
789 | * Called when opening the device. It creates and populates the PCM |
790 | * structure |
791 | * |
792 | */ |
793 | |
794 | static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream) |
795 | { |
796 | struct snd_pcm_runtime *runtime = substream->runtime; |
797 | snd_card_saa7134_pcm_t *pcm; |
798 | snd_card_saa7134_t *saa7134 = snd_pcm_substream_chip(substream); |
799 | struct saa7134_dev *dev; |
800 | int amux, err; |
801 | |
802 | if (!saa7134) { |
803 | pr_err("BUG: saa7134 can't find device struct. Can't proceed with open\n" ); |
804 | return -ENODEV; |
805 | } |
806 | dev = saa7134->dev; |
807 | mutex_lock(&dev->dmasound.lock); |
808 | |
809 | dev->dmasound.read_count = 0; |
810 | dev->dmasound.read_offset = 0; |
811 | |
812 | amux = dev->input->amux; |
813 | if ((amux < 1) || (amux > 3)) |
814 | amux = 1; |
815 | dev->dmasound.input = amux - 1; |
816 | |
817 | mutex_unlock(lock: &dev->dmasound.lock); |
818 | |
819 | pcm = kzalloc(size: sizeof(*pcm), GFP_KERNEL); |
820 | if (pcm == NULL) |
821 | return -ENOMEM; |
822 | |
823 | pcm->dev=saa7134->dev; |
824 | |
825 | spin_lock_init(&pcm->lock); |
826 | |
827 | pcm->substream = substream; |
828 | runtime->private_data = pcm; |
829 | runtime->private_free = snd_card_saa7134_runtime_free; |
830 | runtime->hw = snd_card_saa7134_capture; |
831 | |
832 | if (dev->ctl_mute != 0) { |
833 | saa7134->mute_was_on = 1; |
834 | dev->ctl_mute = 0; |
835 | saa7134_tvaudio_setmute(dev); |
836 | } |
837 | |
838 | err = snd_pcm_hw_constraint_integer(runtime, |
839 | SNDRV_PCM_HW_PARAM_PERIODS); |
840 | if (err < 0) |
841 | return err; |
842 | |
843 | err = snd_pcm_hw_constraint_step(runtime, cond: 0, |
844 | SNDRV_PCM_HW_PARAM_PERIODS, step: 2); |
845 | if (err < 0) |
846 | return err; |
847 | |
848 | return 0; |
849 | } |
850 | |
851 | /* |
852 | * page callback (needed for mmap) |
853 | */ |
854 | |
855 | static struct page *snd_card_saa7134_page(struct snd_pcm_substream *substream, |
856 | unsigned long offset) |
857 | { |
858 | void *pageptr = substream->runtime->dma_area + offset; |
859 | return vmalloc_to_page(addr: pageptr); |
860 | } |
861 | |
862 | /* |
863 | * ALSA capture callbacks definition |
864 | */ |
865 | |
866 | static const struct snd_pcm_ops snd_card_saa7134_capture_ops = { |
867 | .open = snd_card_saa7134_capture_open, |
868 | .close = snd_card_saa7134_capture_close, |
869 | .hw_params = snd_card_saa7134_hw_params, |
870 | .hw_free = snd_card_saa7134_hw_free, |
871 | .prepare = snd_card_saa7134_capture_prepare, |
872 | .trigger = snd_card_saa7134_capture_trigger, |
873 | .pointer = snd_card_saa7134_capture_pointer, |
874 | .page = snd_card_saa7134_page, |
875 | }; |
876 | |
877 | /* |
878 | * ALSA PCM setup |
879 | * |
880 | * Called when initializing the board. Sets up the name and hooks up |
881 | * the callbacks |
882 | * |
883 | */ |
884 | |
885 | static int snd_card_saa7134_pcm(snd_card_saa7134_t *saa7134, int device) |
886 | { |
887 | struct snd_pcm *pcm; |
888 | int err; |
889 | |
890 | if ((err = snd_pcm_new(card: saa7134->card, id: "SAA7134 PCM" , device, playback_count: 0, capture_count: 1, rpcm: &pcm)) < 0) |
891 | return err; |
892 | snd_pcm_set_ops(pcm, direction: SNDRV_PCM_STREAM_CAPTURE, ops: &snd_card_saa7134_capture_ops); |
893 | pcm->private_data = saa7134; |
894 | pcm->info_flags = 0; |
895 | strscpy(p: pcm->name, q: "SAA7134 PCM" , size: sizeof(pcm->name)); |
896 | return 0; |
897 | } |
898 | |
899 | #define SAA713x_VOLUME(xname, xindex, addr) \ |
900 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
901 | .info = snd_saa7134_volume_info, \ |
902 | .get = snd_saa7134_volume_get, .put = snd_saa7134_volume_put, \ |
903 | .private_value = addr } |
904 | |
905 | static int snd_saa7134_volume_info(struct snd_kcontrol * kcontrol, |
906 | struct snd_ctl_elem_info * uinfo) |
907 | { |
908 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
909 | uinfo->count = 2; |
910 | uinfo->value.integer.min = 0; |
911 | uinfo->value.integer.max = 20; |
912 | return 0; |
913 | } |
914 | |
915 | static int snd_saa7134_volume_get(struct snd_kcontrol * kcontrol, |
916 | struct snd_ctl_elem_value * ucontrol) |
917 | { |
918 | snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); |
919 | int addr = kcontrol->private_value; |
920 | |
921 | ucontrol->value.integer.value[0] = chip->mixer_volume[addr][0]; |
922 | ucontrol->value.integer.value[1] = chip->mixer_volume[addr][1]; |
923 | return 0; |
924 | } |
925 | |
926 | static int snd_saa7134_volume_put(struct snd_kcontrol * kcontrol, |
927 | struct snd_ctl_elem_value * ucontrol) |
928 | { |
929 | snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); |
930 | struct saa7134_dev *dev = chip->dev; |
931 | |
932 | int change, addr = kcontrol->private_value; |
933 | int left, right; |
934 | |
935 | left = ucontrol->value.integer.value[0]; |
936 | if (left < 0) |
937 | left = 0; |
938 | if (left > 20) |
939 | left = 20; |
940 | right = ucontrol->value.integer.value[1]; |
941 | if (right < 0) |
942 | right = 0; |
943 | if (right > 20) |
944 | right = 20; |
945 | spin_lock_irq(lock: &chip->mixer_lock); |
946 | change = 0; |
947 | if (chip->mixer_volume[addr][0] != left) { |
948 | change = 1; |
949 | right = left; |
950 | } |
951 | if (chip->mixer_volume[addr][1] != right) { |
952 | change = 1; |
953 | left = right; |
954 | } |
955 | if (change) { |
956 | switch (dev->pci->device) { |
957 | case PCI_DEVICE_ID_PHILIPS_SAA7134: |
958 | switch (addr) { |
959 | case MIXER_ADDR_TVTUNER: |
960 | left = 20; |
961 | break; |
962 | case MIXER_ADDR_LINE1: |
963 | saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x10, |
964 | (left > 10) ? 0x00 : 0x10); |
965 | break; |
966 | case MIXER_ADDR_LINE2: |
967 | saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x20, |
968 | (left > 10) ? 0x00 : 0x20); |
969 | break; |
970 | } |
971 | break; |
972 | case PCI_DEVICE_ID_PHILIPS_SAA7133: |
973 | case PCI_DEVICE_ID_PHILIPS_SAA7135: |
974 | switch (addr) { |
975 | case MIXER_ADDR_TVTUNER: |
976 | left = 20; |
977 | break; |
978 | case MIXER_ADDR_LINE1: |
979 | saa_andorb(0x0594, 0x10, |
980 | (left > 10) ? 0x00 : 0x10); |
981 | break; |
982 | case MIXER_ADDR_LINE2: |
983 | saa_andorb(0x0594, 0x20, |
984 | (left > 10) ? 0x00 : 0x20); |
985 | break; |
986 | } |
987 | break; |
988 | } |
989 | chip->mixer_volume[addr][0] = left; |
990 | chip->mixer_volume[addr][1] = right; |
991 | } |
992 | spin_unlock_irq(lock: &chip->mixer_lock); |
993 | return change; |
994 | } |
995 | |
996 | #define SAA713x_CAPSRC(xname, xindex, addr) \ |
997 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ |
998 | .info = snd_saa7134_capsrc_info, \ |
999 | .get = snd_saa7134_capsrc_get, .put = snd_saa7134_capsrc_put, \ |
1000 | .private_value = addr } |
1001 | |
1002 | static int snd_saa7134_capsrc_info(struct snd_kcontrol * kcontrol, |
1003 | struct snd_ctl_elem_info * uinfo) |
1004 | { |
1005 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
1006 | uinfo->count = 2; |
1007 | uinfo->value.integer.min = 0; |
1008 | uinfo->value.integer.max = 1; |
1009 | return 0; |
1010 | } |
1011 | |
1012 | static int snd_saa7134_capsrc_get(struct snd_kcontrol * kcontrol, |
1013 | struct snd_ctl_elem_value * ucontrol) |
1014 | { |
1015 | snd_card_saa7134_t *chip = snd_kcontrol_chip(kcontrol); |
1016 | int addr = kcontrol->private_value; |
1017 | |
1018 | spin_lock_irq(lock: &chip->mixer_lock); |
1019 | if (chip->capture_source_addr == addr) { |
1020 | ucontrol->value.integer.value[0] = chip->capture_source[0]; |
1021 | ucontrol->value.integer.value[1] = chip->capture_source[1]; |
1022 | } else { |
1023 | ucontrol->value.integer.value[0] = 0; |
1024 | ucontrol->value.integer.value[1] = 0; |
1025 | } |
1026 | spin_unlock_irq(lock: &chip->mixer_lock); |
1027 | |
1028 | return 0; |
1029 | } |
1030 | |
1031 | static int snd_saa7134_capsrc_put(struct snd_kcontrol * kcontrol, |
1032 | struct snd_ctl_elem_value * ucontrol) |
1033 | { |
1034 | int left, right; |
1035 | left = ucontrol->value.integer.value[0] & 1; |
1036 | right = ucontrol->value.integer.value[1] & 1; |
1037 | |
1038 | return snd_saa7134_capsrc_set(kcontrol, left, right, force_notify: false); |
1039 | } |
1040 | |
1041 | static struct snd_kcontrol_new snd_saa7134_volume_controls[] = { |
1042 | SAA713x_VOLUME("Video Volume" , 0, MIXER_ADDR_TVTUNER), |
1043 | SAA713x_VOLUME("Line Volume" , 1, MIXER_ADDR_LINE1), |
1044 | SAA713x_VOLUME("Line Volume" , 2, MIXER_ADDR_LINE2), |
1045 | }; |
1046 | |
1047 | static struct snd_kcontrol_new snd_saa7134_capture_controls[] = { |
1048 | SAA713x_CAPSRC("Video Capture Switch" , 0, MIXER_ADDR_TVTUNER), |
1049 | SAA713x_CAPSRC("Line Capture Switch" , 1, MIXER_ADDR_LINE1), |
1050 | SAA713x_CAPSRC("Line Capture Switch" , 2, MIXER_ADDR_LINE2), |
1051 | }; |
1052 | |
1053 | /* |
1054 | * ALSA mixer setup |
1055 | * |
1056 | * Called when initializing the board. Sets up the name and hooks up |
1057 | * the callbacks |
1058 | * |
1059 | */ |
1060 | |
1061 | static int snd_card_saa7134_new_mixer(snd_card_saa7134_t * chip) |
1062 | { |
1063 | struct snd_card *card = chip->card; |
1064 | struct snd_kcontrol *kcontrol; |
1065 | unsigned int idx; |
1066 | int err, addr; |
1067 | |
1068 | strscpy(p: card->mixername, q: "SAA7134 Mixer" , size: sizeof(card->mixername)); |
1069 | |
1070 | for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_volume_controls); idx++) { |
1071 | kcontrol = snd_ctl_new1(kcontrolnew: &snd_saa7134_volume_controls[idx], |
1072 | private_data: chip); |
1073 | err = snd_ctl_add(card, kcontrol); |
1074 | if (err < 0) |
1075 | return err; |
1076 | } |
1077 | |
1078 | for (idx = 0; idx < ARRAY_SIZE(snd_saa7134_capture_controls); idx++) { |
1079 | kcontrol = snd_ctl_new1(kcontrolnew: &snd_saa7134_capture_controls[idx], |
1080 | private_data: chip); |
1081 | addr = snd_saa7134_capture_controls[idx].private_value; |
1082 | chip->capture_ctl[addr] = kcontrol; |
1083 | err = snd_ctl_add(card, kcontrol); |
1084 | if (err < 0) |
1085 | return err; |
1086 | } |
1087 | |
1088 | chip->capture_source_addr = MIXER_ADDR_UNSELECTED; |
1089 | return 0; |
1090 | } |
1091 | |
1092 | static void snd_saa7134_free(struct snd_card * card) |
1093 | { |
1094 | snd_card_saa7134_t *chip = card->private_data; |
1095 | |
1096 | if (chip->dev->dmasound.priv_data == NULL) |
1097 | return; |
1098 | |
1099 | if (chip->irq >= 0) |
1100 | free_irq(chip->irq, &chip->dev->dmasound); |
1101 | |
1102 | chip->dev->dmasound.priv_data = NULL; |
1103 | |
1104 | } |
1105 | |
1106 | /* |
1107 | * ALSA initialization |
1108 | * |
1109 | * Called by the init routine, once for each saa7134 device present, |
1110 | * it creates the basic structures and registers the ALSA devices |
1111 | * |
1112 | */ |
1113 | |
1114 | static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) |
1115 | { |
1116 | |
1117 | struct snd_card *card; |
1118 | snd_card_saa7134_t *chip; |
1119 | int err; |
1120 | |
1121 | |
1122 | if (devnum >= SNDRV_CARDS) |
1123 | return -ENODEV; |
1124 | if (!enable[devnum]) |
1125 | return -ENODEV; |
1126 | |
1127 | err = snd_card_new(parent: &dev->pci->dev, idx: index[devnum], xid: id[devnum], |
1128 | THIS_MODULE, extra_size: sizeof(snd_card_saa7134_t), card_ret: &card); |
1129 | if (err < 0) |
1130 | return err; |
1131 | |
1132 | strscpy(p: card->driver, q: "SAA7134" , size: sizeof(card->driver)); |
1133 | |
1134 | /* Card "creation" */ |
1135 | |
1136 | card->private_free = snd_saa7134_free; |
1137 | chip = card->private_data; |
1138 | |
1139 | spin_lock_init(&chip->lock); |
1140 | spin_lock_init(&chip->mixer_lock); |
1141 | |
1142 | chip->dev = dev; |
1143 | |
1144 | chip->card = card; |
1145 | |
1146 | chip->pci = dev->pci; |
1147 | chip->iobase = pci_resource_start(dev->pci, 0); |
1148 | |
1149 | |
1150 | err = request_irq(irq: dev->pci->irq, handler: saa7134_alsa_irq, |
1151 | IRQF_SHARED, name: dev->name, |
1152 | dev: (void*) &dev->dmasound); |
1153 | |
1154 | if (err < 0) { |
1155 | pr_err("%s: can't get IRQ %d for ALSA\n" , |
1156 | dev->name, dev->pci->irq); |
1157 | goto __nodev; |
1158 | } |
1159 | |
1160 | chip->irq = dev->pci->irq; |
1161 | |
1162 | mutex_init(&dev->dmasound.lock); |
1163 | |
1164 | if ((err = snd_card_saa7134_new_mixer(chip)) < 0) |
1165 | goto __nodev; |
1166 | |
1167 | if ((err = snd_card_saa7134_pcm(saa7134: chip, device: 0)) < 0) |
1168 | goto __nodev; |
1169 | |
1170 | /* End of "creation" */ |
1171 | |
1172 | strscpy(p: card->shortname, q: "SAA7134" , size: sizeof(card->shortname)); |
1173 | sprintf(buf: card->longname, fmt: "%s at 0x%lx irq %d" , |
1174 | chip->dev->name, chip->iobase, chip->irq); |
1175 | |
1176 | pr_info("%s/alsa: %s registered as card %d\n" , |
1177 | dev->name, card->longname, index[devnum]); |
1178 | |
1179 | if ((err = snd_card_register(card)) == 0) { |
1180 | snd_saa7134_cards[devnum] = card; |
1181 | return 0; |
1182 | } |
1183 | |
1184 | __nodev: |
1185 | snd_card_free(card); |
1186 | return err; |
1187 | } |
1188 | |
1189 | |
1190 | static int alsa_device_init(struct saa7134_dev *dev) |
1191 | { |
1192 | dev->dmasound.priv_data = dev; |
1193 | alsa_card_saa7134_create(dev,devnum: dev->nr); |
1194 | return 1; |
1195 | } |
1196 | |
1197 | static int alsa_device_exit(struct saa7134_dev *dev) |
1198 | { |
1199 | if (!snd_saa7134_cards[dev->nr]) |
1200 | return 1; |
1201 | |
1202 | snd_card_free(card: snd_saa7134_cards[dev->nr]); |
1203 | snd_saa7134_cards[dev->nr] = NULL; |
1204 | return 1; |
1205 | } |
1206 | |
1207 | /* |
1208 | * Module initializer |
1209 | * |
1210 | * Loops through present saa7134 cards, and assigns an ALSA device |
1211 | * to each one |
1212 | * |
1213 | */ |
1214 | |
1215 | static int saa7134_alsa_init(void) |
1216 | { |
1217 | struct saa7134_dev *dev; |
1218 | |
1219 | saa7134_dmasound_init = alsa_device_init; |
1220 | saa7134_dmasound_exit = alsa_device_exit; |
1221 | |
1222 | pr_info("saa7134 ALSA driver for DMA sound loaded\n" ); |
1223 | |
1224 | list_for_each_entry(dev, &saa7134_devlist, devlist) { |
1225 | if (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7130) |
1226 | pr_info("%s/alsa: %s doesn't support digital audio\n" , |
1227 | dev->name, saa7134_boards[dev->board].name); |
1228 | else |
1229 | alsa_device_init(dev); |
1230 | } |
1231 | |
1232 | if (list_empty(head: &saa7134_devlist)) |
1233 | pr_info("saa7134 ALSA: no saa7134 cards found\n" ); |
1234 | |
1235 | return 0; |
1236 | |
1237 | } |
1238 | |
1239 | /* |
1240 | * Module destructor |
1241 | */ |
1242 | |
1243 | static void saa7134_alsa_exit(void) |
1244 | { |
1245 | int idx; |
1246 | |
1247 | for (idx = 0; idx < SNDRV_CARDS; idx++) { |
1248 | if (snd_saa7134_cards[idx]) |
1249 | snd_card_free(card: snd_saa7134_cards[idx]); |
1250 | } |
1251 | |
1252 | saa7134_dmasound_init = NULL; |
1253 | saa7134_dmasound_exit = NULL; |
1254 | pr_info("saa7134 ALSA driver for DMA sound unloaded\n" ); |
1255 | |
1256 | return; |
1257 | } |
1258 | |
1259 | /* We initialize this late, to make sure the sound system is up and running */ |
1260 | late_initcall(saa7134_alsa_init); |
1261 | module_exit(saa7134_alsa_exit); |
1262 | MODULE_LICENSE("GPL" ); |
1263 | MODULE_AUTHOR("Ricardo Cerqueira" ); |
1264 | |