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