brintos

brintos / linux-shallow public Read only

0
0
Text · 23.2 KiB · 29fb131 Raw
1008 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Support for audio capture4 *  PCI function #1 of the cx2388x.5 *6 *    (c) 2007 Trent Piepho <xyzzy@speakeasy.org>7 *    (c) 2005,2006 Ricardo Cerqueira <v4l@cerqueira.org>8 *    (c) 2005 Mauro Carvalho Chehab <mchehab@kernel.org>9 *    Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>10 *    Based on dummy.c by Jaroslav Kysela <perex@perex.cz>11 */12 13#include "cx88.h"14#include "cx88-reg.h"15 16#include <linux/module.h>17#include <linux/init.h>18#include <linux/delay.h>19#include <linux/device.h>20#include <linux/interrupt.h>21#include <linux/vmalloc.h>22#include <linux/dma-mapping.h>23#include <linux/pci.h>24#include <linux/slab.h>25 26#include <sound/core.h>27#include <sound/pcm.h>28#include <sound/pcm_params.h>29#include <sound/control.h>30#include <sound/initval.h>31#include <sound/tlv.h>32#include <media/i2c/wm8775.h>33 34#define dprintk(level, fmt, arg...) do {				\35	if (debug + 1 > level)						\36		printk(KERN_DEBUG pr_fmt("%s: alsa: " fmt),		\37			chip->core->name, ##arg);			\38} while (0)39 40/*41 * Data type declarations - Can be moded to a header file later42 */43 44struct cx88_audio_buffer {45	unsigned int		bpl;46	struct cx88_riscmem	risc;47	void			*vaddr;48	struct scatterlist	*sglist;49	int                     sglen;50	unsigned long		nr_pages;51};52 53struct cx88_audio_dev {54	struct cx88_core           *core;55	struct cx88_dmaqueue       q;56 57	/* pci i/o */58	struct pci_dev             *pci;59 60	/* audio controls */61	int                        irq;62 63	struct snd_card            *card;64 65	spinlock_t                 reg_lock;66	atomic_t		   count;67 68	unsigned int               dma_size;69	unsigned int               period_size;70	unsigned int               num_periods;71 72	struct cx88_audio_buffer   *buf;73 74	struct snd_pcm_substream   *substream;75};76 77/*78 * Module global static vars79 */80 81static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */82static const char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */83static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;84 85module_param_array(enable, bool, NULL, 0444);86MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled.");87 88module_param_array(index, int, NULL, 0444);89MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s).");90 91/*92 * Module macros93 */94 95MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");96MODULE_AUTHOR("Ricardo Cerqueira");97MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@kernel.org>");98MODULE_LICENSE("GPL v2");99MODULE_VERSION(CX88_VERSION);100 101static unsigned int debug;102module_param(debug, int, 0644);103MODULE_PARM_DESC(debug, "enable debug messages");104 105/*106 * Module specific functions107 */108 109/*110 * BOARD Specific: Sets audio DMA111 */112 113static int _cx88_start_audio_dma(struct cx88_audio_dev *chip)114{115	struct cx88_audio_buffer *buf = chip->buf;116	struct cx88_core *core = chip->core;117	const struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];118 119	/* Make sure RISC/FIFO are off before changing FIFO/RISC settings */120	cx_clear(MO_AUD_DMACNTRL, 0x11);121 122	/* setup fifo + format - out channel */123	cx88_sram_channel_setup(chip->core, audio_ch, buf->bpl, buf->risc.dma);124 125	/* sets bpl size */126	cx_write(MO_AUDD_LNGTH, buf->bpl);127 128	/* reset counter */129	cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);130	atomic_set(&chip->count, 0);131 132	dprintk(1,133		"Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d byte buffer\n",134		buf->bpl, cx_read(audio_ch->cmds_start + 8) >> 1,135		chip->num_periods, buf->bpl * chip->num_periods);136 137	/* Enables corresponding bits at AUD_INT_STAT */138	cx_write(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |139				AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);140 141	/* Clean any pending interrupt bits already set */142	cx_write(MO_AUD_INTSTAT, ~0);143 144	/* enable audio irqs */145	cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT);146 147	/* start dma */148 149	/* Enables Risc Processor */150	cx_set(MO_DEV_CNTRL2, (1 << 5));151	/* audio downstream FIFO and RISC enable */152	cx_set(MO_AUD_DMACNTRL, 0x11);153 154	if (debug)155		cx88_sram_channel_dump(chip->core, audio_ch);156 157	return 0;158}159 160/*161 * BOARD Specific: Resets audio DMA162 */163static int _cx88_stop_audio_dma(struct cx88_audio_dev *chip)164{165	struct cx88_core *core = chip->core;166 167	dprintk(1, "Stopping audio DMA\n");168 169	/* stop dma */170	cx_clear(MO_AUD_DMACNTRL, 0x11);171 172	/* disable irqs */173	cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);174	cx_clear(MO_AUD_INTMSK, AUD_INT_OPC_ERR | AUD_INT_DN_SYNC |175				AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1);176 177	if (debug)178		cx88_sram_channel_dump(chip->core,179				       &cx88_sram_channels[SRAM_CH25]);180 181	return 0;182}183 184#define MAX_IRQ_LOOP 50185 186/*187 * BOARD Specific: IRQ dma bits188 */189static const char *cx88_aud_irqs[32] = {190	"dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */191	NULL,					  /* reserved */192	"dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */193	NULL,					  /* reserved */194	"dnf_of", "upf_uf", "rds_dnf_uf",	  /* 8-10 */195	NULL,					  /* reserved */196	"dn_sync", "up_sync", "rds_dn_sync",	  /* 12-14 */197	NULL,					  /* reserved */198	"opc_err", "par_err", "rip_err",	  /* 16-18 */199	"pci_abort", "ber_irq", "mchg_irq"	  /* 19-21 */200};201 202/*203 * BOARD Specific: Threats IRQ audio specific calls204 */205static void cx8801_aud_irq(struct cx88_audio_dev *chip)206{207	struct cx88_core *core = chip->core;208	u32 status, mask;209 210	status = cx_read(MO_AUD_INTSTAT);211	mask   = cx_read(MO_AUD_INTMSK);212	if (0 == (status & mask))213		return;214	cx_write(MO_AUD_INTSTAT, status);215	if (debug > 1  ||  (status & mask & ~0xff))216		cx88_print_irqbits("irq aud",217				   cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs),218				   status, mask);219	/* risc op code error */220	if (status & AUD_INT_OPC_ERR) {221		pr_warn("Audio risc op code error\n");222		cx_clear(MO_AUD_DMACNTRL, 0x11);223		cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]);224	}225	if (status & AUD_INT_DN_SYNC) {226		dprintk(1, "Downstream sync error\n");227		cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET);228		return;229	}230	/* risc1 downstream */231	if (status & AUD_INT_DN_RISCI1) {232		atomic_set(&chip->count, cx_read(MO_AUDD_GPCNT));233		snd_pcm_period_elapsed(chip->substream);234	}235	/* FIXME: Any other status should deserve a special handling? */236}237 238/*239 * BOARD Specific: Handles IRQ calls240 */241static irqreturn_t cx8801_irq(int irq, void *dev_id)242{243	struct cx88_audio_dev *chip = dev_id;244	struct cx88_core *core = chip->core;245	u32 status;246	int loop, handled = 0;247 248	for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {249		status = cx_read(MO_PCI_INTSTAT) &250			(core->pci_irqmask | PCI_INT_AUDINT);251		if (status == 0)252			goto out;253		dprintk(3, "cx8801_irq loop %d/%d, status %x\n",254			loop, MAX_IRQ_LOOP, status);255		handled = 1;256		cx_write(MO_PCI_INTSTAT, status);257 258		if (status & core->pci_irqmask)259			cx88_core_irq(core, status);260		if (status & PCI_INT_AUDINT)261			cx8801_aud_irq(chip);262	}263 264	if (loop == MAX_IRQ_LOOP) {265		pr_err("IRQ loop detected, disabling interrupts\n");266		cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT);267	}268 269 out:270	return IRQ_RETVAL(handled);271}272 273static int cx88_alsa_dma_init(struct cx88_audio_dev *chip,274			      unsigned long nr_pages)275{276	struct cx88_audio_buffer *buf = chip->buf;277	struct page *pg;278	int i;279 280	buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);281	if (!buf->vaddr) {282		dprintk(1, "vmalloc_32(%lu pages) failed\n", nr_pages);283		return -ENOMEM;284	}285 286	dprintk(1, "vmalloc is at addr %p, size=%lu\n",287		buf->vaddr, nr_pages << PAGE_SHIFT);288 289	memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);290	buf->nr_pages = nr_pages;291 292	buf->sglist = vzalloc(array_size(sizeof(*buf->sglist), buf->nr_pages));293	if (!buf->sglist)294		goto vzalloc_err;295 296	sg_init_table(buf->sglist, buf->nr_pages);297	for (i = 0; i < buf->nr_pages; i++) {298		pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE);299		if (!pg)300			goto vmalloc_to_page_err;301		sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0);302	}303	return 0;304 305vmalloc_to_page_err:306	vfree(buf->sglist);307	buf->sglist = NULL;308vzalloc_err:309	vfree(buf->vaddr);310	buf->vaddr = NULL;311	return -ENOMEM;312}313 314static int cx88_alsa_dma_map(struct cx88_audio_dev *dev)315{316	struct cx88_audio_buffer *buf = dev->buf;317 318	buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist,319			buf->nr_pages, DMA_FROM_DEVICE);320 321	if (buf->sglen == 0) {322		pr_warn("%s: cx88_alsa_map_sg failed\n", __func__);323		return -ENOMEM;324	}325	return 0;326}327 328static int cx88_alsa_dma_unmap(struct cx88_audio_dev *dev)329{330	struct cx88_audio_buffer *buf = dev->buf;331 332	if (!buf->sglen)333		return 0;334 335	dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->nr_pages,336		     DMA_FROM_DEVICE);337	buf->sglen = 0;338	return 0;339}340 341static int cx88_alsa_dma_free(struct cx88_audio_buffer *buf)342{343	vfree(buf->sglist);344	buf->sglist = NULL;345	vfree(buf->vaddr);346	buf->vaddr = NULL;347	return 0;348}349 350static int dsp_buffer_free(struct cx88_audio_dev *chip)351{352	struct cx88_riscmem *risc = &chip->buf->risc;353 354	WARN_ON(!chip->dma_size);355 356	dprintk(2, "Freeing buffer\n");357	cx88_alsa_dma_unmap(chip);358	cx88_alsa_dma_free(chip->buf);359	if (risc->cpu)360		dma_free_coherent(&chip->pci->dev, risc->size, risc->cpu,361				  risc->dma);362	kfree(chip->buf);363 364	chip->buf = NULL;365 366	return 0;367}368 369/*370 * ALSA PCM Interface371 */372 373/*374 * Digital hardware definition375 */376#define DEFAULT_FIFO_SIZE	4096377static const struct snd_pcm_hardware snd_cx88_digital_hw = {378	.info = SNDRV_PCM_INFO_MMAP |379		SNDRV_PCM_INFO_INTERLEAVED |380		SNDRV_PCM_INFO_BLOCK_TRANSFER |381		SNDRV_PCM_INFO_MMAP_VALID,382	.formats = SNDRV_PCM_FMTBIT_S16_LE,383 384	.rates =		SNDRV_PCM_RATE_48000,385	.rate_min =		48000,386	.rate_max =		48000,387	.channels_min = 2,388	.channels_max = 2,389	/*390	 * Analog audio output will be full of clicks and pops if there391	 * are not exactly four lines in the SRAM FIFO buffer.392	 */393	.period_bytes_min = DEFAULT_FIFO_SIZE / 4,394	.period_bytes_max = DEFAULT_FIFO_SIZE / 4,395	.periods_min = 1,396	.periods_max = 1024,397	.buffer_bytes_max = (1024 * 1024),398};399 400/*401 * audio pcm capture open callback402 */403static int snd_cx88_pcm_open(struct snd_pcm_substream *substream)404{405	struct cx88_audio_dev *chip = snd_pcm_substream_chip(substream);406	struct snd_pcm_runtime *runtime = substream->runtime;407	int err;408 409	if (!chip) {410		pr_err("BUG: cx88 can't find device struct. Can't proceed with open\n");411		return -ENODEV;412	}413 414	err = snd_pcm_hw_constraint_pow2(runtime, 0,415					 SNDRV_PCM_HW_PARAM_PERIODS);416	if (err < 0)417		goto _error;418 419	chip->substream = substream;420 421	runtime->hw = snd_cx88_digital_hw;422 423	if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) {424		unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4;425 426		bpl &= ~7; /* must be multiple of 8 */427		runtime->hw.period_bytes_min = bpl;428		runtime->hw.period_bytes_max = bpl;429	}430 431	return 0;432_error:433	dprintk(1, "Error opening PCM!\n");434	return err;435}436 437/*438 * audio close callback439 */440static int snd_cx88_close(struct snd_pcm_substream *substream)441{442	return 0;443}444 445/*446 * hw_params callback447 */448static int snd_cx88_hw_params(struct snd_pcm_substream *substream,449			      struct snd_pcm_hw_params *hw_params)450{451	struct cx88_audio_dev *chip = snd_pcm_substream_chip(substream);452 453	struct cx88_audio_buffer *buf;454	int ret;455 456	if (substream->runtime->dma_area) {457		dsp_buffer_free(chip);458		substream->runtime->dma_area = NULL;459	}460 461	chip->period_size = params_period_bytes(hw_params);462	chip->num_periods = params_periods(hw_params);463	chip->dma_size = chip->period_size * params_periods(hw_params);464 465	WARN_ON(!chip->dma_size);466	WARN_ON(chip->num_periods & (chip->num_periods - 1));467 468	buf = kzalloc(sizeof(*buf), GFP_KERNEL);469	if (!buf)470		return -ENOMEM;471 472	chip->buf = buf;473	buf->bpl = chip->period_size;474 475	ret = cx88_alsa_dma_init(chip,476				 (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));477	if (ret < 0)478		goto error;479 480	ret = cx88_alsa_dma_map(chip);481	if (ret < 0)482		goto error;483 484	ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->sglist,485				   chip->period_size, chip->num_periods, 1);486	if (ret < 0)487		goto error;488 489	/* Loop back to start of program */490	buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);491	buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);492 493	substream->runtime->dma_area = chip->buf->vaddr;494	substream->runtime->dma_bytes = chip->dma_size;495	substream->runtime->dma_addr = 0;496	return 0;497 498error:499	kfree(buf);500	return ret;501}502 503/*504 * hw free callback505 */506static int snd_cx88_hw_free(struct snd_pcm_substream *substream)507{508	struct cx88_audio_dev *chip = snd_pcm_substream_chip(substream);509 510	if (substream->runtime->dma_area) {511		dsp_buffer_free(chip);512		substream->runtime->dma_area = NULL;513	}514 515	return 0;516}517 518/*519 * prepare callback520 */521static int snd_cx88_prepare(struct snd_pcm_substream *substream)522{523	return 0;524}525 526/*527 * trigger callback528 */529static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd)530{531	struct cx88_audio_dev *chip = snd_pcm_substream_chip(substream);532	int err;533 534	/* Local interrupts are already disabled by ALSA */535	spin_lock(&chip->reg_lock);536 537	switch (cmd) {538	case SNDRV_PCM_TRIGGER_START:539		err = _cx88_start_audio_dma(chip);540		break;541	case SNDRV_PCM_TRIGGER_STOP:542		err = _cx88_stop_audio_dma(chip);543		break;544	default:545		err =  -EINVAL;546		break;547	}548 549	spin_unlock(&chip->reg_lock);550 551	return err;552}553 554/*555 * pointer callback556 */557static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)558{559	struct cx88_audio_dev *chip = snd_pcm_substream_chip(substream);560	struct snd_pcm_runtime *runtime = substream->runtime;561	u16 count;562 563	count = atomic_read(&chip->count);564 565//	dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __func__,566//		count, new, count & (runtime->periods-1),567//		runtime->period_size * (count & (runtime->periods-1)));568	return runtime->period_size * (count & (runtime->periods - 1));569}570 571/*572 * page callback (needed for mmap)573 */574static struct page *snd_cx88_page(struct snd_pcm_substream *substream,575				  unsigned long offset)576{577	void *pageptr = substream->runtime->dma_area + offset;578 579	return vmalloc_to_page(pageptr);580}581 582/*583 * operators584 */585static const struct snd_pcm_ops snd_cx88_pcm_ops = {586	.open = snd_cx88_pcm_open,587	.close = snd_cx88_close,588	.hw_params = snd_cx88_hw_params,589	.hw_free = snd_cx88_hw_free,590	.prepare = snd_cx88_prepare,591	.trigger = snd_cx88_card_trigger,592	.pointer = snd_cx88_pointer,593	.page = snd_cx88_page,594};595 596/*597 * create a PCM device598 */599static int snd_cx88_pcm(struct cx88_audio_dev *chip, int device,600			const char *name)601{602	int err;603	struct snd_pcm *pcm;604 605	err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);606	if (err < 0)607		return err;608	pcm->private_data = chip;609	strscpy(pcm->name, name, sizeof(pcm->name));610	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops);611 612	return 0;613}614 615/*616 * CONTROL INTERFACE617 */618static int snd_cx88_volume_info(struct snd_kcontrol *kcontrol,619				struct snd_ctl_elem_info *info)620{621	info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;622	info->count = 2;623	info->value.integer.min = 0;624	info->value.integer.max = 0x3f;625 626	return 0;627}628 629static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol,630			       struct snd_ctl_elem_value *value)631{632	struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol);633	struct cx88_core *core = chip->core;634	int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f),635	    bal = cx_read(AUD_BAL_CTL);636 637	value->value.integer.value[(bal & 0x40) ? 0 : 1] = vol;638	vol -= (bal & 0x3f);639	value->value.integer.value[(bal & 0x40) ? 1 : 0] = vol < 0 ? 0 : vol;640 641	return 0;642}643 644static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol,645				       struct snd_ctl_elem_value *value)646{647	struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol);648	struct cx88_core *core = chip->core;649	u16 left = value->value.integer.value[0];650	u16 right = value->value.integer.value[1];651	int v, b;652 653	/* Pass volume & balance onto any WM8775 */654	if (left >= right) {655		v = left << 10;656		b = left ? (0x8000 * right) / left : 0x8000;657	} else {658		v = right << 10;659		b = right ? 0xffff - (0x8000 * left) / right : 0x8000;660	}661	wm8775_s_ctrl(core, V4L2_CID_AUDIO_VOLUME, v);662	wm8775_s_ctrl(core, V4L2_CID_AUDIO_BALANCE, b);663}664 665/* OK - TODO: test it */666static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,667			       struct snd_ctl_elem_value *value)668{669	struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol);670	struct cx88_core *core = chip->core;671	int left, right, v, b;672	int changed = 0;673	u32 old;674 675	if (core->sd_wm8775)676		snd_cx88_wm8775_volume_put(kcontrol, value);677 678	left = value->value.integer.value[0] & 0x3f;679	right = value->value.integer.value[1] & 0x3f;680	b = right - left;681	if (b < 0) {682		v = 0x3f - left;683		b = (-b) | 0x40;684	} else {685		v = 0x3f - right;686	}687	/* Do we really know this will always be called with IRQs on? */688	spin_lock_irq(&chip->reg_lock);689	old = cx_read(AUD_VOL_CTL);690	if (v != (old & 0x3f)) {691		cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, (old & ~0x3f) | v);692		changed = 1;693	}694	if ((cx_read(AUD_BAL_CTL) & 0x7f) != b) {695		cx_write(AUD_BAL_CTL, b);696		changed = 1;697	}698	spin_unlock_irq(&chip->reg_lock);699 700	return changed;701}702 703static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0);704 705static const struct snd_kcontrol_new snd_cx88_volume = {706	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,707	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |708		  SNDRV_CTL_ELEM_ACCESS_TLV_READ,709	.name = "Analog-TV Volume",710	.info = snd_cx88_volume_info,711	.get = snd_cx88_volume_get,712	.put = snd_cx88_volume_put,713	.tlv.p = snd_cx88_db_scale,714};715 716static int snd_cx88_switch_get(struct snd_kcontrol *kcontrol,717			       struct snd_ctl_elem_value *value)718{719	struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol);720	struct cx88_core *core = chip->core;721	u32 bit = kcontrol->private_value;722 723	value->value.integer.value[0] = !(cx_read(AUD_VOL_CTL) & bit);724	return 0;725}726 727static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,728			       struct snd_ctl_elem_value *value)729{730	struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol);731	struct cx88_core *core = chip->core;732	u32 bit = kcontrol->private_value;733	int ret = 0;734	u32 vol;735 736	spin_lock_irq(&chip->reg_lock);737	vol = cx_read(AUD_VOL_CTL);738	if (value->value.integer.value[0] != !(vol & bit)) {739		vol ^= bit;740		cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol);741		/* Pass mute onto any WM8775 */742		if (core->sd_wm8775 && ((1 << 6) == bit))743			wm8775_s_ctrl(core,744				      V4L2_CID_AUDIO_MUTE, 0 != (vol & bit));745		ret = 1;746	}747	spin_unlock_irq(&chip->reg_lock);748	return ret;749}750 751static const struct snd_kcontrol_new snd_cx88_dac_switch = {752	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,753	.name = "Audio-Out Switch",754	.info = snd_ctl_boolean_mono_info,755	.get = snd_cx88_switch_get,756	.put = snd_cx88_switch_put,757	.private_value = (1 << 8),758};759 760static const struct snd_kcontrol_new snd_cx88_source_switch = {761	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,762	.name = "Analog-TV Switch",763	.info = snd_ctl_boolean_mono_info,764	.get = snd_cx88_switch_get,765	.put = snd_cx88_switch_put,766	.private_value = (1 << 6),767};768 769static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol,770			    struct snd_ctl_elem_value *value)771{772	struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol);773	struct cx88_core *core = chip->core;774	s32 val;775 776	val = wm8775_g_ctrl(core, V4L2_CID_AUDIO_LOUDNESS);777	value->value.integer.value[0] = val ? 1 : 0;778	return 0;779}780 781static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol,782			    struct snd_ctl_elem_value *value)783{784	struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol);785	struct cx88_core *core = chip->core;786 787	wm8775_s_ctrl(core, V4L2_CID_AUDIO_LOUDNESS,788		      value->value.integer.value[0] != 0);789	return 0;790}791 792static const struct snd_kcontrol_new snd_cx88_alc_switch = {793	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,794	.name = "Line-In ALC Switch",795	.info = snd_ctl_boolean_mono_info,796	.get = snd_cx88_alc_get,797	.put = snd_cx88_alc_put,798};799 800/*801 * Basic Flow for Sound Devices802 */803 804/*805 * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio806 * Only boards with eeprom and byte 1 at eeprom=1 have it807 */808 809static const struct pci_device_id cx88_audio_pci_tbl[] = {810	{0x14f1, 0x8801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},811	{0x14f1, 0x8811, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},812	{0, }813};814MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);815 816/*817 * Chip-specific destructor818 */819 820static int snd_cx88_free(struct cx88_audio_dev *chip)821{822	if (chip->irq >= 0)823		free_irq(chip->irq, chip);824 825	cx88_core_put(chip->core, chip->pci);826 827	pci_disable_device(chip->pci);828	return 0;829}830 831/*832 * Component Destructor833 */834static void snd_cx88_dev_free(struct snd_card *card)835{836	struct cx88_audio_dev *chip = card->private_data;837 838	snd_cx88_free(chip);839}840 841/*842 * Alsa Constructor - Component probe843 */844 845static int devno;846static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci,847			   struct cx88_audio_dev **rchip,848			   struct cx88_core **core_ptr)849{850	struct cx88_audio_dev	*chip;851	struct cx88_core	*core;852	int			err;853	unsigned char		pci_lat;854 855	*rchip = NULL;856 857	err = pci_enable_device(pci);858	if (err < 0)859		return err;860 861	pci_set_master(pci);862 863	chip = card->private_data;864 865	core = cx88_core_get(pci);866	if (!core) {867		err = -EINVAL;868		return err;869	}870 871	err = dma_set_mask(&pci->dev, DMA_BIT_MASK(32));872	if (err) {873		dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n", core->name);874		cx88_core_put(core, pci);875		return err;876	}877 878	/* pci init */879	chip->card = card;880	chip->pci = pci;881	chip->irq = -1;882	spin_lock_init(&chip->reg_lock);883 884	chip->core = core;885 886	/* get irq */887	err = request_irq(chip->pci->irq, cx8801_irq,888			  IRQF_SHARED, chip->core->name, chip);889	if (err < 0) {890		dprintk(0, "%s: can't get IRQ %d\n",891			chip->core->name, chip->pci->irq);892		return err;893	}894 895	/* print pci info */896	pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat);897 898	dprintk(1,899		"ALSA %s/%i: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n",900		core->name, devno,901		pci_name(pci), pci->revision, pci->irq,902		pci_lat, (unsigned long long)pci_resource_start(pci, 0));903 904	chip->irq = pci->irq;905	synchronize_irq(chip->irq);906 907	*rchip = chip;908	*core_ptr = core;909 910	return 0;911}912 913static int cx88_audio_initdev(struct pci_dev *pci,914			      const struct pci_device_id *pci_id)915{916	struct snd_card		*card;917	struct cx88_audio_dev	*chip;918	struct cx88_core	*core = NULL;919	int			err;920 921	if (devno >= SNDRV_CARDS)922		return (-ENODEV);923 924	if (!enable[devno]) {925		++devno;926		return (-ENOENT);927	}928 929	err = snd_card_new(&pci->dev, index[devno], id[devno], THIS_MODULE,930			   sizeof(struct cx88_audio_dev), &card);931	if (err < 0)932		return err;933 934	card->private_free = snd_cx88_dev_free;935 936	err = snd_cx88_create(card, pci, &chip, &core);937	if (err < 0)938		goto error;939 940	err = snd_cx88_pcm(chip, 0, "CX88 Digital");941	if (err < 0)942		goto error;943 944	err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_volume, chip));945	if (err < 0)946		goto error;947	err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_dac_switch, chip));948	if (err < 0)949		goto error;950	err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_source_switch, chip));951	if (err < 0)952		goto error;953 954	/* If there's a wm8775 then add a Line-In ALC switch */955	if (core->sd_wm8775) {956		err = snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip));957		if (err < 0)958			goto error;959	}960 961	strscpy(card->driver, "CX88x", sizeof(card->driver));962	sprintf(card->shortname, "Conexant CX%x", pci->device);963	sprintf(card->longname, "%s at %#llx",964		card->shortname,965		(unsigned long long)pci_resource_start(pci, 0));966	strscpy(card->mixername, "CX88", sizeof(card->mixername));967 968	dprintk(0, "%s/%i: ALSA support for cx2388x boards\n",969		card->driver, devno);970 971	err = snd_card_register(card);972	if (err < 0)973		goto error;974	pci_set_drvdata(pci, card);975 976	devno++;977	return 0;978 979error:980	snd_card_free(card);981	return err;982}983 984/*985 * ALSA destructor986 */987static void cx88_audio_finidev(struct pci_dev *pci)988{989	struct snd_card *card = pci_get_drvdata(pci);990 991	snd_card_free(card);992 993	devno--;994}995 996/*997 * PCI driver definition998 */999 1000static struct pci_driver cx88_audio_pci_driver = {1001	.name     = "cx88_audio",1002	.id_table = cx88_audio_pci_tbl,1003	.probe    = cx88_audio_initdev,1004	.remove   = cx88_audio_finidev,1005};1006 1007module_pci_driver(cx88_audio_pci_driver);1008