summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video')
-rw-r--r--linux/drivers/media/video/cx88/cx88-alsa.c668
-rw-r--r--linux/drivers/media/video/cx88/cx88.h15
2 files changed, 635 insertions, 48 deletions
diff --git a/linux/drivers/media/video/cx88/cx88-alsa.c b/linux/drivers/media/video/cx88/cx88-alsa.c
index 58496bf1c..c4b2b1ddf 100644
--- a/linux/drivers/media/video/cx88/cx88-alsa.c
+++ b/linux/drivers/media/video/cx88/cx88-alsa.c
@@ -1,10 +1,13 @@
/*
- * $Id: cx88-alsa.c,v 1.4 2005/07/15 21:44:14 mchehab Exp $
+ * $Id: cx88-alsa.c,v 1.5 2005/08/10 17:01:28 mchehab Exp $
*
* Support for audio capture
* PCI function #1 of the cx2388x.
*
- * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2005 Mauro Carvalho Chehab <mchehab@brturbo.com.br>
+ * Based on a dummy cx88 module by Gerd Knorr <kraxel@bytesex.org>
+ * Based on bt87x.c by Clemens Ladisch <clemens@ladisch.de>
+ * Based on dummy.c by Jaroslav Kysela <perex@suse.cz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,22 +29,117 @@
#include <linux/device.h>
#include <linux/interrupt.h>
#include <asm/delay.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/control.h>
+#include <sound/initval.h>
#include "compat.h"
#include "cx88.h"
-/* ------------------------------------------------------------------ */
+/****************************************************************************
+ Data type declarations - Can be moded to a header file later
+ ****************************************************************************/
-MODULE_DESCRIPTION("alsa driver module for cx2388x based TV cards");
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+#if 1
+#define ANALOG_CLOCK 1792000
+#define CLOCK_DIV_MIN 4
+#define CLOCK_DIV_MAX 15
+#define MAX_PCM_DEVICES 4
+#define MAX_PCM_SUBSTREAMS 16
+#endif
+
+enum { DEVICE_DIGITAL, DEVICE_ANALOG };
+
+/* These can be replaced after done */
+#define MIXER_ADDR_LAST MAX_CX88_INPUT
+//#define SNDRV_CARDS CX88_MAXBOARDS
+
+struct cx88_audio_dev {
+ struct cx88_core *core;
+ struct cx88_buffer *buf;
+ struct cx88_dmaqueue *q;
+
+ /* pci i/o */
+ struct pci_dev *pci;
+ unsigned char pci_rev,pci_lat;
+
+ /* audio controls */
+ int dig_rate; /* Digital sampling rate */
+
+ snd_card_t *card;
+
+ spinlock_t reg_lock;
+
+ unsigned int dma_size;
+ unsigned int period_size;
+
+ int mixer_volume[MIXER_ADDR_LAST+1][2];
+ int capture_source[MIXER_ADDR_LAST+1][2];
+
+ long opened;
+ snd_pcm_substream_t *substream;
+};
+typedef struct cx88_audio_dev snd_cx88_card_t;
+
+/****************************************************************************
+ Module global static vars
+ ****************************************************************************/
+
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
+static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
+static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
+
+static snd_cx88_card_t *snd_dummy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
+
+/****************************************************************************
+ Module macros
+ ****************************************************************************/
+
+MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@brturbo.com.br>");
MODULE_LICENSE("GPL");
-/* ------------------------------------------------------------------ */
+/****************************************************************************
+ Part 1: Basic Flow for Sound Devices
+ ****************************************************************************/
+/*
+ * PCI ID Table
+ */
-static int __devinit cx8801_initdev(struct pci_dev *pci_dev,
+struct pci_device_id cx88_audio_pci_tbl[] = {
+ {
+ .vendor = 0x14f1,
+ .device = 0x8800,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },{
+ .vendor = 0x14f1,
+ .device = 0x8801,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },{
+ .vendor = 0x14f1,
+ .device = 0x8811,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },{
+ /* --- end of list --- */
+ }
+};
+MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
+
+/*
+ * Alsa Constructor - Component probe
+ */
+static int __devinit cx88_audio_initdev(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
- struct cx8801_dev *dev;
+ snd_cx88_card_t *dev;
struct cx88_core *core;
int err;
@@ -52,7 +150,7 @@ static int __devinit cx8801_initdev(struct pci_dev *pci_dev,
/* pci init */
dev->pci = pci_dev;
- if (pci_enable_device(pci_dev)) {
+ if (pci_enable_device(pci_dev)) {
err = -EIO;
goto fail_free;
}
@@ -78,7 +176,7 @@ static int __devinit cx8801_initdev(struct pci_dev *pci_dev,
goto fail_core;
}
- printk("%s/1: no alsa support yet, this is just a dummy module\n",
+ printk("%s/1: Alsa support for cx2388x boards\n",
core->name);
pci_set_drvdata(pci_dev,dev);
return 0;
@@ -90,9 +188,12 @@ static int __devinit cx8801_initdev(struct pci_dev *pci_dev,
return err;
}
-static void __devexit cx8801_finidev(struct pci_dev *pci_dev)
+/*
+ * ALSA destructor
+ */
+static void __devexit cx88_audio_finidev(struct pci_dev *pci_dev)
{
- struct cx8801_dev *dev = pci_get_drvdata(pci_dev);
+ snd_cx88_card_t *dev = pci_get_drvdata(pci_dev);
pci_disable_device(pci_dev);
@@ -104,35 +205,521 @@ static void __devexit cx8801_finidev(struct pci_dev *pci_dev)
kfree(dev);
}
-struct pci_device_id cx8801_pci_tbl[] = {
- {
- .vendor = 0x14f1,
- .device = 0x8801,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },{
- .vendor = 0x14f1,
- .device = 0x8811,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- },{
- /* --- end of list --- */
+/*
+ * PCI driver definition
+ */
+
+static struct pci_driver cx88_audio_pci_driver = {
+ .name = "cx88_audio",
+ .id_table = cx88_audio_pci_tbl,
+ .probe = cx88_audio_initdev,
+ .remove = cx88_audio_finidev,
+#if 0
+ .suspend = cx88_audio_suspend,
+ .resume = cx88_audio_resume,
+#endif
+};
+
+/*
+ =====================> FIXME
+ */
+
+#if 0
+static void snd_cx88_pci_error(bt87x_t *chip, unsigned int status)
+{
+ u16 pci_status;
+
+ pci_read_config_word(chip->pci, PCI_STATUS, &pci_status);
+ pci_status &= PCI_STATUS_PARITY | PCI_STATUS_SIG_TARGET_ABORT |
+ PCI_STATUS_REC_TARGET_ABORT | PCI_STATUS_REC_MASTER_ABORT |
+ PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY;
+ pci_write_config_word(chip->pci, PCI_STATUS, pci_status);
+ if (pci_status != PCI_STATUS_DETECTED_PARITY)
+ snd_printk(KERN_ERR "Aieee - PCI error! status %#08x, PCI status %#04x\n",
+ status & ERROR_INTERRUPTS, pci_status);
+ else {
+ snd_printk(KERN_ERR "Aieee - PCI parity error detected!\n");
+ /* error 'handling' similar to aic7xxx_pci.c: */
+ chip->pci_parity_errors++;
+ if (chip->pci_parity_errors > 20) {
+ snd_printk(KERN_ERR "Too many PCI parity errors observed.\n");
+ snd_printk(KERN_ERR "Some device on this bus is generating bad parity.\n");
+ snd_printk(KERN_ERR "This is an error *observed by*, not *generated by*, this card.\n");
+ snd_printk(KERN_ERR "PCI parity error checking has been disabled.\n");
+ chip->interrupt_mask &= ~(INT_PPERR | INT_RIPERR);
+ snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask);
+ }
+ }
+}
+#endif
+
+/****************************************************************************
+ ALSA PCM Interface
+ ****************************************************************************/
+
+/*
+ * Digital hardware definition
+ */
+static snd_pcm_hardware_t snd_cx88_digital_hw = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ .rates = 0, /* set at runtime */
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 255 * 4092,
+ .period_bytes_min = 32,
+ .period_bytes_max = 4092,
+ .periods_min = 2,
+ .periods_max = 255,
+};
+
+/*
+ * Analog hardware definition
+ */
+static snd_pcm_hardware_t snd_cx88_analog_hw = {
+ .info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S8,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = ANALOG_CLOCK / CLOCK_DIV_MAX,
+ .rate_max = ANALOG_CLOCK / CLOCK_DIV_MIN,
+ .channels_min = 1,
+ .channels_max = 1,
+ .buffer_bytes_max = 255 * 4092,
+ .period_bytes_min = 32,
+ .period_bytes_max = 4092,
+ .periods_min = 2,
+ .periods_max = 255,
+};
+
+/*
+ * Sets board to provide digital audio
+ */
+static int snd_cx88_set_digital_hw(snd_cx88_card_t *chip, snd_pcm_runtime_t *runtime)
+{
+ static struct {
+ int rate;
+ unsigned int bit;
+ } ratebits[] = {
+ {8000, SNDRV_PCM_RATE_8000},
+ {11025, SNDRV_PCM_RATE_11025},
+ {16000, SNDRV_PCM_RATE_16000},
+ {22050, SNDRV_PCM_RATE_22050},
+ {32000, SNDRV_PCM_RATE_32000},
+ {44100, SNDRV_PCM_RATE_44100},
+ {48000, SNDRV_PCM_RATE_48000}
+ };
+ int i;
+#if 0
+ chip->reg_control |= CTL_DA_IOM_DA;
+#endif
+ runtime->hw = snd_cx88_digital_hw;
+ runtime->hw.rates = SNDRV_PCM_RATE_KNOT;
+ for (i = 0; i < ARRAY_SIZE(ratebits); ++i)
+ if (chip->dig_rate == ratebits[i].rate) {
+ runtime->hw.rates = ratebits[i].bit;
+ break;
+ }
+ runtime->hw.rate_min = chip->dig_rate;
+ runtime->hw.rate_max = chip->dig_rate;
+ return 0;
+}
+
+/*
+ * Sets board to provide analog audio
+ */
+static int snd_cx88_set_analog_hw(snd_cx88_card_t *core, snd_pcm_runtime_t *runtime)
+{
+ static ratnum_t analog_clock = {
+ .num = ANALOG_CLOCK,
+ .den_min = CLOCK_DIV_MIN,
+ .den_max = CLOCK_DIV_MAX,
+ .den_step = 1
+ };
+ static snd_pcm_hw_constraint_ratnums_t constraint_rates = {
+ .nrats = 1,
+ .rats = &analog_clock
+ };
+
+#if 0
+ chip->reg_control &= ~CTL_DA_IOM_DA;
+#endif
+ runtime->hw = snd_cx88_analog_hw;
+ return snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ &constraint_rates);
+}
+
+/*
+ * audio open callback
+ */
+static int snd_cx88_pcm_open(snd_pcm_substream_t *substream)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int err;
+
+ if (test_and_set_bit(0, &chip->opened))
+ return -EBUSY;
+
+ if (substream->pcm->device == DEVICE_DIGITAL)
+ err = snd_cx88_set_digital_hw(chip, runtime);
+ else
+ err = snd_cx88_set_analog_hw(chip, runtime);
+ if (err < 0)
+ goto _error;
+
+ err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+ if (err < 0)
+ goto _error;
+
+ chip->substream = substream;
+ return 0;
+
+_error:
+ clear_bit(0, &chip->opened);
+ smp_mb__after_clear_bit();
+ return err;
+}
+
+/*
+ * audio close callback
+ */
+static int snd_cx88_close(snd_pcm_substream_t *substream)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+
+ chip->substream = NULL;
+ clear_bit(0, &chip->opened);
+ smp_mb__after_clear_bit();
+ return 0;
+}
+
+/*
+ * hw_params callback
+ */
+static int snd_cx88_hw_params(snd_pcm_substream_t * substream,
+ snd_pcm_hw_params_t * hw_params)
+{
+ return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
+}
+
+/*
+ * hw free callback
+ */
+static int snd_cx88_hw_free(snd_pcm_substream_t * substream)
+{
+ return snd_pcm_lib_free_pages(substream);
+}
+
+/*
+ * prepare callback
+ */
+static int snd_cx88_prepare(snd_pcm_substream_t *substream)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+ int decimation;
+
+ spin_lock_irq(&chip->reg_lock);
+
+ chip->dma_size = snd_pcm_lib_buffer_bytes(substream);
+ chip->period_size = snd_pcm_lib_period_bytes(substream);
+#if 0
+ chip->reg_control &= ~(CTL_DA_SDR_MASK | CTL_DA_SBR);
+ decimation = (ANALOG_CLOCK + runtime->rate / 4) / runtime->rate;
+ chip->reg_control |= decimation << CTL_DA_SDR_SHIFT;
+ if (runtime->format == SNDRV_PCM_FORMAT_S8)
+ chip->reg_control |= CTL_DA_SBR;
+ snd_bt87x_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
+
+ outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
+ outl(ES_MEM_PAGEO(ES_PAGE_DAC), ES_REG(ensoniq, MEM_PAGE));
+ outl(runtime->dma_addr, ES_REG(ensoniq, DAC1_FRAME));
+ outl((ensoniq->p1_dma_size >> 2) - 1, ES_REG(ensoniq, DAC1_SIZE));
+ ensoniq->sctrl &= ~(ES_P1_LOOP_SEL | ES_P1_PAUSE | ES_P1_SCT_RLD | ES_P1_MODEM);
+ ensoniq->sctrl |= ES_P1_INT_EN | ES_P1_MODEO(mode);
+ outl(ensoniq->sctrl, ES_REG(ensoniq, SERIAL));
+ outl((ensoniq->p1_period_size >> snd_ensoniq_sample_shift[mode]) - 1, ES_REG(ensoniq, DAC1_COUNT));
+#endif
+ spin_unlock_irq(&chip->reg_lock);
+ return 0;
+}
+
+/*
+ * BOARD Specific: Sets audio DMA
+ * FIXME: move to cx88-core
+ */
+
+static int start_audio_dma(snd_cx88_card_t *dev)
+{
+ struct cx88_core *core = dev->core;
+#if 0
+ /* setup fifo + format - out channel */
+ cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26],
+ dev->buf->bpl, dev->buf->risc.dma1);
+#endif
+
+ /* FIXME reset counter */
+ cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET);
+
+ /* enable irqs */
+ cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
+
+ /* Enables corresponding bits at AUD_INT_STAT */
+#if 1
+ cx_set(MO_AUD_INTMSK, (1<<21)||(1<<19));
+#endif
+
+ /* start dma */
+ cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */
+ cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */
+
+ return 0;
+}
+
+/*
+ * BOARD Specific: Resets audio DMA
+ * FIXME: move to cx88-core
+ */
+static int stop_audio_dma(snd_cx88_card_t *dev)
+{
+ struct cx88_core *core = dev->core;
+
+ /* stop dma */
+ cx_clear(MO_AUD_DMACNTRL, 0x11);
+
+ /* disable irqs */
+ cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x01);
+
+/* FIXME: Should only be cleared if video is also disabled
+ * Can be a counter - when zero, clear intmask.
+ */
+#if 0
+ cx_clear(MO_PCI_INTMSK, 0x000001);
+#endif
+ cx_set(MO_AUD_INTMSK, 0);
+ return 0;
+}
+
+/*
+ * trigger callback
+ */
+static int snd_cx88_card_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+// return snd_cx88_start(chip);
+ case SNDRV_PCM_TRIGGER_STOP:
+// return snd_cx88_stop(chip);
+ default:
+ return -EINVAL;
}
+}
+
+/*
+ * pointer callback
+ */
+static snd_pcm_uframes_t snd_cx88_pointer(snd_pcm_substream_t *substream)
+{
+ snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
+ snd_pcm_runtime_t *runtime = substream->runtime;
+
+// return (snd_pcm_uframes_t)bytes_to_frames(runtime, chip->current_line * chip->line_bytes);
+}
+
+/*
+ * operators
+ */
+static snd_pcm_ops_t snd_cx88_pcm_ops = {
+ .open = snd_cx88_pcm_open,
+ .close = snd_cx88_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = snd_cx88_hw_params,
+ .hw_free = snd_cx88_hw_free,
+ .prepare = snd_cx88_prepare,
+ .trigger = snd_cx88_card_trigger,
+ .pointer = snd_cx88_pointer,
+ .page = snd_pcm_sgbuf_ops_page,
+};
+
+/*
+ * create a PCM device
+ */
+static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name)
+{
+ int err;
+#if 0
+ snd_cx88_pcm_t *pcm;
+
+ err = snd_pcm_new(chip->card, name, device, 0, 1, &pcm);
+ if (err < 0)
+ return err;
+ pcm->private_data = chip;
+ strcpy(pcm->name, name);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_cx88_pcm_ops);
+ return snd_pcm_lib_preallocate_pages_for_all(pcm,
+ SNDRV_DMA_TYPE_DEV_SG,
+ snd_dma_pci_data(chip->pci),
+ 128 * 1024,
+ (255 * 4092 + 1023) & ~1023);
+#endif
+}
+
+/****************************************************************************
+ CONTROL INTERFACE
+ ****************************************************************************/
+static int snd_cx88_capture_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = 1;
+ info->value.integer.min = 0;
+ info->value.integer.max = 15;
+ return 0;
+}
+
+static int snd_cx88_capture_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+
+#if 0
+ value->value.integer.value[0] = (chip->reg_control & CTL_A_GAIN_MASK) >> CTL_A_GAIN_SHIFT;
+#endif
+ return 0;
+}
+
+static int snd_cx88_capture_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ u32 old_control;
+ int changed;
+
+#if 0
+ spin_lock_irq(&chip->reg_lock);
+ old_control = chip->reg_control;
+ chip->reg_control = (chip->reg_control & ~CTL_A_GAIN_MASK)
+ | (value->value.integer.value[0] << CTL_A_GAIN_SHIFT);
+ snd_cx88_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
+ changed = old_control != chip->reg_control;
+ spin_unlock_irq(&chip->reg_lock);
+#endif
+ return changed;
+}
+
+static snd_kcontrol_new_t snd_cx88_capture_volume = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Volume",
+ .info = snd_cx88_capture_volume_info,
+ .get = snd_cx88_capture_volume_get,
+ .put = snd_cx88_capture_volume_put,
};
-MODULE_DEVICE_TABLE(pci, cx8801_pci_tbl);
-static struct pci_driver cx8801_pci_driver = {
- .name = "cx8801",
- .id_table = cx8801_pci_tbl,
- .probe = cx8801_initdev,
- .remove = cx8801_finidev,
+static int snd_cx88_capture_boost_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
+{
+ info->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ info->count = 1;
+ info->value.integer.min = 0;
+ info->value.integer.max = 1;
+ return 0;
+}
+
+static int snd_cx88_capture_boost_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
#if 0
- .suspend = cx8801_suspend,
- .resume = cx8801_resume,
+ value->value.integer.value[0] = !! (chip->reg_control & CTL_A_G2X);
#endif
+ return 0;
+}
+
+static int snd_cx88_capture_boost_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ u32 old_control;
+ int changed;
+
+#if 0
+ spin_lock_irq(&chip->reg_lock);
+ old_control = chip->reg_control;
+ chip->reg_control = (chip->reg_control & ~CTL_A_G2X)
+ | (value->value.integer.value[0] ? CTL_A_G2X : 0);
+ snd_cx88_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
+ changed = chip->reg_control != old_control;
+ spin_unlock_irq(&chip->reg_lock);
+#endif
+ return changed;
+}
+
+static snd_kcontrol_new_t snd_cx88_capture_boost = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Boost",
+ .info = snd_cx88_capture_boost_info,
+ .get = snd_cx88_capture_boost_get,
+ .put = snd_cx88_capture_boost_put,
+};
+
+static int snd_cx88_capture_source_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *info)
+{
+ static char *texts[3] = {"TV Tuner", "FM", "Mic/Line"};
+
+ info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ info->count = 1;
+ info->value.enumerated.items = 3;
+ if (info->value.enumerated.item > 2)
+ info->value.enumerated.item = 2;
+ strcpy(info->value.enumerated.name, texts[info->value.enumerated.item]);
+ return 0;
+}
+
+static int snd_cx88_capture_source_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+#if 0
+ value->value.enumerated.item[0] = (chip->reg_control & CTL_A_SEL_MASK) >> CTL_A_SEL_SHIFT;
+#endif
+ return 0;
+}
+
+static int snd_cx88_capture_source_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *value)
+{
+ snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol);
+ u32 old_control;
+ int changed;
+#if 0
+ spin_lock_irq(&chip->reg_lock);
+ old_control = chip->reg_control;
+ chip->reg_control = (chip->reg_control & ~CTL_A_SEL_MASK)
+ | (value->value.enumerated.item[0] << CTL_A_SEL_SHIFT);
+ snd_cx88_writel(chip, REG_GPIO_DMA_CTL, chip->reg_control);
+ changed = chip->reg_control != old_control;
+ spin_unlock_irq(&chip->reg_lock);
+#endif
+ return changed;
+}
+
+static snd_kcontrol_new_t snd_cx88_capture_source = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Capture Source",
+ .info = snd_cx88_capture_source_info,
+ .get = snd_cx88_capture_source_get,
+ .put = snd_cx88_capture_source_put,
};
-static int cx8801_init(void)
+
+/****************************************************************************
+ LINUX MODULE INIT
+ ****************************************************************************/
+
+/*
+ * module init
+ */
+static int cx88_audio_init(void)
{
printk(KERN_INFO "cx2388x alsa driver version %d.%d.%d loaded\n",
(CX88_VERSION_CODE >> 16) & 0xff,
@@ -142,16 +729,19 @@ static int cx8801_init(void)
printk(KERN_INFO "cx2388x: snapshot date %04d-%02d-%02d\n",
SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100);
#endif
- return pci_module_init(&cx8801_pci_driver);
+ return pci_module_init(&cx88_audio_pci_driver);
}
-static void cx8801_fini(void)
+/*
+ * module remove
+ */
+static void cx88_audio_fini(void)
{
- pci_unregister_driver(&cx8801_pci_driver);
+ pci_unregister_driver(&cx88_audio_pci_driver);
}
-module_init(cx8801_init);
-module_exit(cx8801_fini);
+module_init(cx88_audio_init);
+module_exit(cx88_audio_fini);
/* ----------------------------------------------------------- */
/*
diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h
index 77b05b18a..72f578bf6 100644
--- a/linux/drivers/media/video/cx88/cx88.h
+++ b/linux/drivers/media/video/cx88/cx88.h
@@ -1,5 +1,5 @@
/*
- * $Id: cx88.h,v 1.70 2005/07/24 17:44:09 mkrufky Exp $
+ * $Id: cx88.h,v 1.71 2005/08/10 17:01:28 mchehab Exp $
*
* v4l2 device driver for cx2388x based TV cards
*
@@ -49,6 +49,9 @@
#define CX88_MAXBOARDS 8
+/* Max number of inputs by card */
+#define MAX_CX88_INPUT 8
+
/* ----------------------------------------------------------- */
/* defines and enums */
@@ -203,7 +206,7 @@ struct cx88_board {
unsigned char tuner_addr;
unsigned char radio_addr;
int tda9887_conf;
- struct cx88_input input[8];
+ struct cx88_input input[MAX_CX88_INPUT];
struct cx88_input radio;
int blackbird:1;
int dvb:1;
@@ -365,14 +368,8 @@ struct cx8800_dev {
/* ----------------------------------------------------------- */
/* function 1: audio/alsa stuff */
+/* =============> moved to cx88-alsa.c <====================== */
-struct cx8801_dev {
- struct cx88_core *core;
-
- /* pci i/o */
- struct pci_dev *pci;
- unsigned char pci_rev,pci_lat;
-};
/* ----------------------------------------------------------- */
/* function 2: mpeg stuff */