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