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