diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 12:13:30 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 16:36:22 -0300 |
commit | b285192a43f0432d82c2c10974204e78af0da596 (patch) | |
tree | 618aa87e760c9c949eca9e4df6ae0eeffa11dcfc /drivers/media/video/cx18 | |
parent | 68de959f773a1d49096835c411390bceff5d1549 (diff) |
[media] rename most media/video pci drivers to media/pci
Rename all PCI drivers with their own directory under
drivers/media/video into drivers/media/pci and update the
building system.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/cx18')
51 files changed, 0 insertions, 15270 deletions
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig deleted file mode 100644 index 53b3c770257..00000000000 --- a/drivers/media/video/cx18/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -config VIDEO_CX18 - tristate "Conexant cx23418 MPEG encoder support" - depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL - select I2C_ALGOBIT - select VIDEOBUF_VMALLOC - depends on RC_CORE - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_CX2341X - select VIDEO_CS5345 - select DVB_S5H1409 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE - select DVB_S5H1411 if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE - select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMISE - ---help--- - This is a video4linux driver for Conexant cx23418 based - PCI combo video recorder devices. - - This is used in devices such as the Hauppauge HVR-1600 - cards. - - To compile this driver as a module, choose M here: the - module will be called cx18. - -config VIDEO_CX18_ALSA - tristate "Conexant 23418 DMA audio support" - depends on VIDEO_CX18 && SND && EXPERIMENTAL - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio on - Conexant 23418 based TV cards using ALSA. - - To compile this driver as a module, choose M here: the - module will be called cx18-alsa. diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile deleted file mode 100644 index d3ff1545c2c..00000000000 --- a/drivers/media/video/cx18/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \ - cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \ - cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \ - cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \ - cx18-dvb.o cx18-io.o -cx18-alsa-objs := cx18-alsa-main.o cx18-alsa-pcm.o - -obj-$(CONFIG_VIDEO_CX18) += cx18.o -obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o - -ccflags-y += -Idrivers/media/dvb-core -ccflags-y += -Idrivers/media/dvb-frontends -ccflags-y += -Idrivers/media/tuners diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c deleted file mode 100644 index 6d2a98246b6..00000000000 --- a/drivers/media/video/cx18/cx18-alsa-main.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> - * Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> - * - * Portions of this work were sponsored by ONELAN Limited. - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/spinlock.h> - -#include <media/v4l2-device.h> - -#include <sound/core.h> -#include <sound/initval.h> - -#include "cx18-driver.h" -#include "cx18-version.h" -#include "cx18-alsa.h" -#include "cx18-alsa-mixer.h" -#include "cx18-alsa-pcm.h" - -int cx18_alsa_debug; - -#define CX18_DEBUG_ALSA_INFO(fmt, arg...) \ - do { \ - if (cx18_alsa_debug & 2) \ - printk(KERN_INFO "%s: " fmt, "cx18-alsa", ## arg); \ - } while (0); - -module_param_named(debug, cx18_alsa_debug, int, 0644); -MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: 0\n" - "\t\t\t 1/0x0001: warning\n" - "\t\t\t 2/0x0002: info\n"); - -MODULE_AUTHOR("Andy Walls"); -MODULE_DESCRIPTION("CX23418 ALSA Interface"); -MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder"); -MODULE_LICENSE("GPL"); - -MODULE_VERSION(CX18_VERSION); - -static inline -struct snd_cx18_card *to_snd_cx18_card(struct v4l2_device *v4l2_dev) -{ - return to_cx18(v4l2_dev)->alsa; -} - -static inline -struct snd_cx18_card *p_to_snd_cx18_card(struct v4l2_device **v4l2_dev) -{ - return container_of(v4l2_dev, struct snd_cx18_card, v4l2_dev); -} - -static void snd_cx18_card_free(struct snd_cx18_card *cxsc) -{ - if (cxsc == NULL) - return; - - if (cxsc->v4l2_dev != NULL) - to_cx18(cxsc->v4l2_dev)->alsa = NULL; - - /* FIXME - take any other stopping actions needed */ - - kfree(cxsc); -} - -static void snd_cx18_card_private_free(struct snd_card *sc) -{ - if (sc == NULL) - return; - snd_cx18_card_free(sc->private_data); - sc->private_data = NULL; - sc->private_free = NULL; -} - -static int snd_cx18_card_create(struct v4l2_device *v4l2_dev, - struct snd_card *sc, - struct snd_cx18_card **cxsc) -{ - *cxsc = kzalloc(sizeof(struct snd_cx18_card), GFP_KERNEL); - if (*cxsc == NULL) - return -ENOMEM; - - (*cxsc)->v4l2_dev = v4l2_dev; - (*cxsc)->sc = sc; - - sc->private_data = *cxsc; - sc->private_free = snd_cx18_card_private_free; - - return 0; -} - -static int snd_cx18_card_set_names(struct snd_cx18_card *cxsc) -{ - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - struct snd_card *sc = cxsc->sc; - - /* sc->driver is used by alsa-lib's configurator: simple, unique */ - strlcpy(sc->driver, "CX23418", sizeof(sc->driver)); - - /* sc->shortname is a symlink in /proc/asound: CX18-M -> cardN */ - snprintf(sc->shortname, sizeof(sc->shortname), "CX18-%d", - cx->instance); - - /* sc->longname is read from /proc/asound/cards */ - snprintf(sc->longname, sizeof(sc->longname), - "CX23418 #%d %s TV/FM Radio/Line-In Capture", - cx->instance, cx->card_name); - - return 0; -} - -static int snd_cx18_init(struct v4l2_device *v4l2_dev) -{ - struct cx18 *cx = to_cx18(v4l2_dev); - struct snd_card *sc = NULL; - struct snd_cx18_card *cxsc; - int ret; - - /* Numbrs steps from "Writing an ALSA Driver" by Takashi Iwai */ - - /* (1) Check and increment the device index */ - /* This is a no-op for us. We'll use the cx->instance */ - - /* (2) Create a card instance */ - ret = snd_card_create(SNDRV_DEFAULT_IDX1, /* use first available id */ - SNDRV_DEFAULT_STR1, /* xid from end of shortname*/ - THIS_MODULE, 0, &sc); - if (ret) { - CX18_ALSA_ERR("%s: snd_card_create() failed with err %d\n", - __func__, ret); - goto err_exit; - } - - /* (3) Create a main component */ - ret = snd_cx18_card_create(v4l2_dev, sc, &cxsc); - if (ret) { - CX18_ALSA_ERR("%s: snd_cx18_card_create() failed with err %d\n", - __func__, ret); - goto err_exit_free; - } - - /* (4) Set the driver ID and name strings */ - snd_cx18_card_set_names(cxsc); - - - ret = snd_cx18_pcm_create(cxsc); - if (ret) { - CX18_ALSA_ERR("%s: snd_cx18_pcm_create() failed with err %d\n", - __func__, ret); - goto err_exit_free; - } - /* FIXME - proc files */ - - /* (7) Set the driver data and return 0 */ - /* We do this out of normal order for PCI drivers to avoid races */ - cx->alsa = cxsc; - - /* (6) Register the card instance */ - ret = snd_card_register(sc); - if (ret) { - cx->alsa = NULL; - CX18_ALSA_ERR("%s: snd_card_register() failed with err %d\n", - __func__, ret); - goto err_exit_free; - } - - return 0; - -err_exit_free: - if (sc != NULL) - snd_card_free(sc); - kfree(cxsc); -err_exit: - return ret; -} - -int cx18_alsa_load(struct cx18 *cx) -{ - struct v4l2_device *v4l2_dev = &cx->v4l2_dev; - struct cx18_stream *s; - - if (v4l2_dev == NULL) { - printk(KERN_ERR "cx18-alsa: %s: struct v4l2_device * is NULL\n", - __func__); - return 0; - } - - cx = to_cx18(v4l2_dev); - if (cx == NULL) { - printk(KERN_ERR "cx18-alsa cx is NULL\n"); - return 0; - } - - s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; - if (s->video_dev == NULL) { - CX18_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - " - "skipping\n", __func__); - return 0; - } - - if (cx->alsa != NULL) { - CX18_ALSA_ERR("%s: struct snd_cx18_card * already exists\n", - __func__); - return 0; - } - - if (snd_cx18_init(v4l2_dev)) { - CX18_ALSA_ERR("%s: failed to create struct snd_cx18_card\n", - __func__); - } else { - CX18_DEBUG_ALSA_INFO("%s: created cx18 ALSA interface instance " - "\n", __func__); - } - return 0; -} - -static int __init cx18_alsa_init(void) -{ - printk(KERN_INFO "cx18-alsa: module loading...\n"); - cx18_ext_init = &cx18_alsa_load; - return 0; -} - -static void __exit snd_cx18_exit(struct snd_cx18_card *cxsc) -{ - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - - /* FIXME - pointer checks & shutdown cxsc */ - - snd_card_free(cxsc->sc); - cx->alsa = NULL; -} - -static int __exit cx18_alsa_exit_callback(struct device *dev, void *data) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); - struct snd_cx18_card *cxsc; - - if (v4l2_dev == NULL) { - printk(KERN_ERR "cx18-alsa: %s: struct v4l2_device * is NULL\n", - __func__); - return 0; - } - - cxsc = to_snd_cx18_card(v4l2_dev); - if (cxsc == NULL) { - CX18_ALSA_WARN("%s: struct snd_cx18_card * is NULL\n", - __func__); - return 0; - } - - snd_cx18_exit(cxsc); - return 0; -} - -static void __exit cx18_alsa_exit(void) -{ - struct device_driver *drv; - int ret; - - printk(KERN_INFO "cx18-alsa: module unloading...\n"); - - drv = driver_find("cx18", &pci_bus_type); - ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback); - (void)ret; /* suppress compiler warning */ - - cx18_ext_init = NULL; - printk(KERN_INFO "cx18-alsa: module unload complete\n"); -} - -module_init(cx18_alsa_init); -module_exit(cx18_alsa_exit); diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.c b/drivers/media/video/cx18/cx18-alsa-mixer.c deleted file mode 100644 index 341bddc00b7..00000000000 --- a/drivers/media/video/cx18/cx18-alsa-mixer.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/device.h> -#include <linux/spinlock.h> -#include <linux/videodev2.h> - -#include <media/v4l2-device.h> - -#include <sound/core.h> -#include <sound/control.h> -#include <sound/tlv.h> - -#include "cx18-alsa.h" -#include "cx18-driver.h" - -/* - * Note the cx18-av-core volume scale is funny, due to the alignment of the - * scale with another chip's range: - * - * v4l2_control value /512 indicated dB actual dB reg 0x8d4 - * 0x0000 - 0x01ff 0 -119 -96 228 - * 0x0200 - 0x02ff 1 -118 -96 228 - * ... - * 0x2c00 - 0x2dff 22 -97 -96 228 - * 0x2e00 - 0x2fff 23 -96 -96 228 - * 0x3000 - 0x31ff 24 -95 -95 226 - * ... - * 0xee00 - 0xefff 119 0 0 36 - * ... - * 0xfe00 - 0xffff 127 +8 +8 20 - */ -static inline int dB_to_cx18_av_vol(int dB) -{ - if (dB < -96) - dB = -96; - else if (dB > 8) - dB = 8; - return (dB + 119) << 9; -} - -static inline int cx18_av_vol_to_dB(int v) -{ - if (v < (23 << 9)) - v = (23 << 9); - else if (v > (127 << 9)) - v = (127 << 9); - return (v >> 9) - 119; -} - -static int snd_cx18_mixer_tv_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - /* We're already translating values, just keep this control in dB */ - uinfo->value.integer.min = -96; - uinfo->value.integer.max = 8; - uinfo->value.integer.step = 1; - return 0; -} - -static int snd_cx18_mixer_tv_vol_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl); - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - - snd_cx18_lock(cxsc); - ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl); - snd_cx18_unlock(cxsc); - - if (!ret) - uctl->value.integer.value[0] = cx18_av_vol_to_dB(vctrl.value); - return ret; -} - -static int snd_cx18_mixer_tv_vol_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) -{ - struct snd_cx18_card *cxsc = snd_kcontrol_chip(kctl); - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - struct v4l2_control vctrl; - int ret; - - vctrl.id = V4L2_CID_AUDIO_VOLUME; - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - - snd_cx18_lock(cxsc); - - /* Fetch current state */ - ret = v4l2_subdev_call(cx->sd_av, core, g_ctrl, &vctrl); - - if (ret || - (cx18_av_vol_to_dB(vctrl.value) != uctl->value.integer.value[0])) { - - /* Set, if needed */ - vctrl.value = dB_to_cx18_av_vol(uctl->value.integer.value[0]); - ret = v4l2_subdev_call(cx->sd_av, core, s_ctrl, &vctrl); - if (!ret) - ret = 1; /* Indicate control was changed w/o error */ - } - snd_cx18_unlock(cxsc); - - return ret; -} - - -/* This is a bit of overkill, the slider is already in dB internally */ -static DECLARE_TLV_DB_SCALE(snd_cx18_mixer_tv_vol_db_scale, -9600, 100, 0); - -static struct snd_kcontrol_new snd_cx18_mixer_tv_vol __initdata = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog TV Capture Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ, - .info = snd_cx18_mixer_tv_volume_info, - .get = snd_cx18_mixer_tv_volume_get, - .put = snd_cx18_mixer_tv_volume_put, - .tlv.p = snd_cx18_mixer_tv_vol_db_scale -}; - -/* FIXME - add mute switch and balance, bass, treble sliders: - V4L2_CID_AUDIO_MUTE - - V4L2_CID_AUDIO_BALANCE - - V4L2_CID_AUDIO_BASS - V4L2_CID_AUDIO_TREBLE -*/ - -/* FIXME - add stereo, lang1, lang2, mono menu */ -/* FIXME - add CS5345 I2S volume for HVR-1600 */ - -int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc) -{ - struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; - struct snd_card *sc = cxsc->sc; - int ret; - - strlcpy(sc->mixername, "CX23418 Mixer", sizeof(sc->mixername)); - - ret = snd_ctl_add(sc, snd_ctl_new1(snd_cx18_mixer_tv_vol, cxsc)); - if (ret) { - CX18_ALSA_WARN("%s: failed to add %s control, err %d\n", - __func__, snd_cx18_mixer_tv_vol.name, ret); - } - return ret; -} diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.h b/drivers/media/video/cx18/cx18-alsa-mixer.h deleted file mode 100644 index ec9238793f6..00000000000 --- a/drivers/media/video/cx18/cx18-alsa-mixer.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * ALSA mixer controls for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -int __init snd_cx18_mixer_create(struct snd_cx18_card *cxsc); diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/video/cx18/cx18-alsa-pcm.c deleted file mode 100644 index 7a5b84a86bb..00000000000 --- a/drivers/media/video/cx18/cx18-alsa-pcm.c +++ /dev/null @@ -1,356 +0,0 @@ -/* - * ALSA PCM device for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> - * Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com> - * - * Portions of this work were sponsored by ONELAN Limited. - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/vmalloc.h> - -#include <media/v4l2-device.h> - -#include <sound/core.h> -#include <sound/pcm.h> - -#include "cx18-driver.h" -#include "cx18-queue.h" -#include "cx18-streams.h" -#include "cx18-fileops.h" -#include "cx18-alsa.h" - -static unsigned int pcm_debug; -module_param(pcm_debug, int, 0644); -MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm"); - -#define dprintk(fmt, arg...) do { \ - if (pcm_debug) \ - printk(KERN_INFO "cx18-alsa-pcm %s: " fmt, \ - __func__, ##arg); \ - } while (0) - -static struct snd_pcm_hardware snd_cx18_hw_capture = { - .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_MMAP_VALID, - - .formats = SNDRV_PCM_FMTBIT_S16_LE, - - .rates = SNDRV_PCM_RATE_48000, - - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ - .period_bytes_min = 64, /* 12544/2, */ - .period_bytes_max = 12544, - .periods_min = 2, - .periods_max = 98, /* 12544, */ -}; - -void cx18_alsa_announce_pcm_data(struct snd_cx18_card *cxsc, u8 *pcm_data, - size_t num_bytes) -{ - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - unsigned int oldptr; - unsigned int stride; - int period_elapsed = 0; - int length; - - dprintk("cx18 alsa announce ptr=%p data=%p num_bytes=%zd\n", cxsc, - pcm_data, num_bytes); - - substream = cxsc->capture_pcm_substream; - if (substream == NULL) { - dprintk("substream was NULL\n"); - return; - } - - runtime = substream->runtime; - if (runtime == NULL) { - dprintk("runtime was NULL\n"); - return; - } - - stride = runtime->frame_bits >> 3; - if (stride == 0) { - dprintk("stride is zero\n"); - return; - } - - length = num_bytes / stride; - if (length == 0) { - dprintk("%s: length was zero\n", __func__); - return; - } - - if (runtime->dma_area == NULL) { - dprintk("dma area was NULL - ignoring\n"); - return; - } - - oldptr = cxsc->hwptr_done_capture; - if (oldptr + length >= runtime->buffer_size) { - unsigned int cnt = - runtime->buffer_size - oldptr; - memcpy(runtime->dma_area + oldptr * stride, pcm_data, - cnt * stride); - memcpy(runtime->dma_area, pcm_data + cnt * stride, - length * stride - cnt * stride); - } else { - memcpy(runtime->dma_area + oldptr * stride, pcm_data, - length * stride); - } - snd_pcm_stream_lock(substream); - - cxsc->hwptr_done_capture += length; - if (cxsc->hwptr_done_capture >= - runtime->buffer_size) - cxsc->hwptr_done_capture -= - runtime->buffer_size; - - cxsc->capture_transfer_done += length; - if (cxsc->capture_transfer_done >= - runtime->period_size) { - cxsc->capture_transfer_done -= - runtime->period_size; - period_elapsed = 1; - } - - snd_pcm_stream_unlock(substream); - - if (period_elapsed) - snd_pcm_period_elapsed(substream); -} - -static int snd_cx18_pcm_capture_open(struct snd_pcm_substream *substream) -{ - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; - struct cx18 *cx = to_cx18(v4l2_dev); - struct cx18_stream *s; - struct cx18_open_id item; - int ret; - - /* Instruct the cx18 to start sending packets */ - snd_cx18_lock(cxsc); - s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; - - item.cx = cx; - item.type = s->type; - item.open_id = cx->open_id++; - - /* See if the stream is available */ - if (cx18_claim_stream(&item, item.type)) { - /* No, it's already in use */ - snd_cx18_unlock(cxsc); - return -EBUSY; - } - - if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || - test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { - /* We're already streaming. No additional action required */ - snd_cx18_unlock(cxsc); - return 0; - } - - - runtime->hw = snd_cx18_hw_capture; - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - cxsc->capture_pcm_substream = substream; - runtime->private_data = cx; - - cx->pcm_announce_callback = cx18_alsa_announce_pcm_data; - - /* Not currently streaming, so start it up */ - set_bit(CX18_F_S_STREAMING, &s->s_flags); - ret = cx18_start_v4l2_encode_stream(s); - snd_cx18_unlock(cxsc); - - return ret; -} - -static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream) -{ - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; - struct cx18 *cx = to_cx18(v4l2_dev); - struct cx18_stream *s; - - /* Instruct the cx18 to stop sending packets */ - snd_cx18_lock(cxsc); - s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; - cx18_stop_v4l2_encode_stream(s, 0); - clear_bit(CX18_F_S_STREAMING, &s->s_flags); - - cx18_release_stream(s); - - cx->pcm_announce_callback = NULL; - snd_cx18_unlock(cxsc); - - return 0; -} - -static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream, - unsigned int cmd, void *arg) -{ - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - int ret; - - snd_cx18_lock(cxsc); - ret = snd_pcm_lib_ioctl(substream, cmd, arg); - snd_cx18_unlock(cxsc); - return ret; -} - - -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, - size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - dprintk("Allocating vbuffer\n"); - if (runtime->dma_area) { - if (runtime->dma_bytes > size) - return 0; - - vfree(runtime->dma_area); - } - runtime->dma_area = vmalloc(size); - if (!runtime->dma_area) - return -ENOMEM; - - runtime->dma_bytes = size; - - return 0; -} - -static int snd_cx18_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *params) -{ - dprintk("%s called\n", __func__); - - return snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(params)); -} - -static int snd_cx18_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - unsigned long flags; - - spin_lock_irqsave(&cxsc->slock, flags); - if (substream->runtime->dma_area) { - dprintk("freeing pcm capture region\n"); - vfree(substream->runtime->dma_area); - substream->runtime->dma_area = NULL; - } - spin_unlock_irqrestore(&cxsc->slock, flags); - - return 0; -} - -static int snd_cx18_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - - cxsc->hwptr_done_capture = 0; - cxsc->capture_transfer_done = 0; - - return 0; -} - -static int snd_cx18_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - return 0; -} - -static -snd_pcm_uframes_t snd_cx18_pcm_pointer(struct snd_pcm_substream *substream) -{ - unsigned long flags; - snd_pcm_uframes_t hwptr_done; - struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); - - spin_lock_irqsave(&cxsc->slock, flags); - hwptr_done = cxsc->hwptr_done_capture; - spin_unlock_irqrestore(&cxsc->slock, flags); - - return hwptr_done; -} - -static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, - unsigned long offset) -{ - void *pageptr = subs->runtime->dma_area + offset; - - return vmalloc_to_page(pageptr); -} - -static struct snd_pcm_ops snd_cx18_pcm_capture_ops = { - .open = snd_cx18_pcm_capture_open, - .close = snd_cx18_pcm_capture_close, - .ioctl = snd_cx18_pcm_ioctl, - .hw_params = snd_cx18_pcm_hw_params, - .hw_free = snd_cx18_pcm_hw_free, - .prepare = snd_cx18_pcm_prepare, - .trigger = snd_cx18_pcm_trigger, - .pointer = snd_cx18_pcm_pointer, - .page = snd_pcm_get_vmalloc_page, -}; - -int snd_cx18_pcm_create(struct snd_cx18_card *cxsc) -{ - struct snd_pcm *sp; - struct snd_card *sc = cxsc->sc; - struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; - struct cx18 *cx = to_cx18(v4l2_dev); - int ret; - - ret = snd_pcm_new(sc, "CX23418 PCM", - 0, /* PCM device 0, the only one for this card */ - 0, /* 0 playback substreams */ - 1, /* 1 capture substream */ - &sp); - if (ret) { - CX18_ALSA_ERR("%s: snd_cx18_pcm_create() failed with err %d\n", - __func__, ret); - goto err_exit; - } - - spin_lock_init(&cxsc->slock); - - snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE, - &snd_cx18_pcm_capture_ops); - sp->info_flags = 0; - sp->private_data = cxsc; - strlcpy(sp->name, cx->card_name, sizeof(sp->name)); - - return 0; - -err_exit: - return ret; -} diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.h b/drivers/media/video/cx18/cx18-alsa-pcm.h deleted file mode 100644 index d26e51f9457..00000000000 --- a/drivers/media/video/cx18/cx18-alsa-pcm.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * ALSA PCM device for the - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -int __init snd_cx18_pcm_create(struct snd_cx18_card *cxsc); - -/* Used by cx18-mailbox to announce the PCM data to the module */ -void cx18_alsa_announce_pcm_data(struct snd_cx18_card *card, u8 *pcm_data, - size_t num_bytes); diff --git a/drivers/media/video/cx18/cx18-alsa.h b/drivers/media/video/cx18/cx18-alsa.h deleted file mode 100644 index 447da374c9e..00000000000 --- a/drivers/media/video/cx18/cx18-alsa.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * ALSA interface to cx18 PCM capture streams - * - * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -struct snd_card; - -struct snd_cx18_card { - struct v4l2_device *v4l2_dev; - struct snd_card *sc; - unsigned int capture_transfer_done; - unsigned int hwptr_done_capture; - struct snd_pcm_substream *capture_pcm_substream; - spinlock_t slock; -}; - -extern int cx18_alsa_debug; - -/* - * File operations that manipulate the encoder or video or audio subdevices - * need to be serialized. Use the same lock we use for v4l2 file ops. - */ -static inline void snd_cx18_lock(struct snd_cx18_card *cxsc) -{ - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - mutex_lock(&cx->serialize_lock); -} - -static inline void snd_cx18_unlock(struct snd_cx18_card *cxsc) -{ - struct cx18 *cx = to_cx18(cxsc->v4l2_dev); - mutex_unlock(&cx->serialize_lock); -} - -#define CX18_ALSA_DBGFLG_WARN (1 << 0) -#define CX18_ALSA_DBGFLG_WARN (1 << 0) -#define CX18_ALSA_DBGFLG_INFO (1 << 1) - -#define CX18_ALSA_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & cx18_alsa_debug) \ - printk(KERN_INFO "%s-alsa: " type ": " fmt, \ - v4l2_dev->name , ## args); \ - } while (0) - -#define CX18_ALSA_DEBUG_WARN(fmt, args...) \ - CX18_ALSA_DEBUG(CX18_ALSA_DBGFLG_WARN, "warning", fmt , ## args) - -#define CX18_ALSA_DEBUG_INFO(fmt, args...) \ - CX18_ALSA_DEBUG(CX18_ALSA_DBGFLG_INFO, "info", fmt , ## args) - -#define CX18_ALSA_ERR(fmt, args...) \ - printk(KERN_ERR "%s-alsa: " fmt, v4l2_dev->name , ## args) - -#define CX18_ALSA_WARN(fmt, args...) \ - printk(KERN_WARNING "%s-alsa: " fmt, v4l2_dev->name , ## args) - -#define CX18_ALSA_INFO(fmt, args...) \ - printk(KERN_INFO "%s-alsa: " fmt, v4l2_dev->name , ## args) diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c deleted file mode 100644 index 35268923911..00000000000 --- a/drivers/media/video/cx18/cx18-audio.c +++ /dev/null @@ -1,92 +0,0 @@ -/* - * cx18 audio-related functions - * - * Derived from ivtv-audio.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-cards.h" -#include "cx18-audio.h" - -#define CX18_AUDIO_ENABLE 0xc72014 -#define CX18_AI1_MUX_MASK 0x30 -#define CX18_AI1_MUX_I2S1 0x00 -#define CX18_AI1_MUX_I2S2 0x10 -#define CX18_AI1_MUX_843_I2S 0x20 - -/* Selects the audio input and output according to the current - settings. */ -int cx18_audio_set_io(struct cx18 *cx) -{ - const struct cx18_card_audio_input *in; - u32 u, v; - int err; - - /* Determine which input to use */ - if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) - in = &cx->card->radio_input; - else - in = &cx->card->audio_inputs[cx->audio_input]; - - /* handle muxer chips */ - v4l2_subdev_call(cx->sd_extmux, audio, s_routing, - (u32) in->muxer_input, 0, 0); - - err = cx18_call_hw_err(cx, cx->card->hw_audio_ctrl, - audio, s_routing, in->audio_input, 0, 0); - if (err) - return err; - - /* FIXME - this internal mux should be abstracted to a subdev */ - u = cx18_read_reg(cx, CX18_AUDIO_ENABLE); - v = u & ~CX18_AI1_MUX_MASK; - switch (in->audio_input) { - case CX18_AV_AUDIO_SERIAL1: - v |= CX18_AI1_MUX_I2S1; - break; - case CX18_AV_AUDIO_SERIAL2: - v |= CX18_AI1_MUX_I2S2; - break; - default: - v |= CX18_AI1_MUX_843_I2S; - break; - } - if (v == u) { - /* force a toggle of some AI1 MUX control bits */ - u &= ~CX18_AI1_MUX_MASK; - switch (in->audio_input) { - case CX18_AV_AUDIO_SERIAL1: - u |= CX18_AI1_MUX_843_I2S; - break; - case CX18_AV_AUDIO_SERIAL2: - u |= CX18_AI1_MUX_843_I2S; - break; - default: - u |= CX18_AI1_MUX_I2S1; - break; - } - cx18_write_reg_expect(cx, u | 0xb00, CX18_AUDIO_ENABLE, - u, CX18_AI1_MUX_MASK); - } - cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, - v, CX18_AI1_MUX_MASK); - return 0; -} diff --git a/drivers/media/video/cx18/cx18-audio.h b/drivers/media/video/cx18/cx18-audio.h deleted file mode 100644 index 2731d29b0ab..00000000000 --- a/drivers/media/video/cx18/cx18-audio.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * cx18 audio-related functions - * - * Derived from ivtv-audio.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -int cx18_audio_set_io(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c deleted file mode 100644 index 4a24ffb17a7..00000000000 --- a/drivers/media/video/cx18/cx18-av-audio.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * cx18 ADEC audio functions - * - * Derived from cx25840-audio.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "cx18-driver.h" - -static int set_audclk_freq(struct cx18 *cx, u32 freq) -{ - struct cx18_av_state *state = &cx->av_state; - - if (freq != 32000 && freq != 44100 && freq != 48000) - return -EINVAL; - - /* - * The PLL parameters are based on the external crystal frequency that - * would ideally be: - * - * NTSC Color subcarrier freq * 8 = - * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz - * - * The accidents of history and rationale that explain from where this - * combination of magic numbers originate can be found in: - * - * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in - * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80 - * - * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the - * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83 - * - * As Mike Bradley has rightly pointed out, it's not the exact crystal - * frequency that matters, only that all parts of the driver and - * firmware are using the same value (close to the ideal value). - * - * Since I have a strong suspicion that, if the firmware ever assumes a - * crystal value at all, it will assume 28.636360 MHz, the crystal - * freq used in calculations in this driver will be: - * - * xtal_freq = 28.636360 MHz - * - * an error of less than 0.13 ppm which is way, way better than any off - * the shelf crystal will have for accuracy anyway. - * - * Below I aim to run the PLLs' VCOs near 400 MHz to minimze error. - * - * Many thanks to Jeff Campbell and Mike Bradley for their extensive - * investigation, experimentation, testing, and suggested solutions of - * of audio/video sync problems with SVideo and CVBS captures. - */ - - if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { - switch (freq) { - case 32000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20 - */ - cx18_av_write4(cx, 0x108, 0x200d040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x176740c */ - /* xtal * 0xd.bb3a060/0x20 = 32000 * 384: 393 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x0176740c); - - /* src3/4/6_ctl */ - /* 0x1.f77f = (4 * xtal/8*2/455) / 32000 */ - cx18_av_write4(cx, 0x900, 0x0801f77f); - cx18_av_write4(cx, 0x904, 0x0801f77f); - cx18_av_write4(cx, 0x90c, 0x0801f77f); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */ - cx18_av_write(cx, 0x127, 0x60); - - /* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */ - cx18_av_write4(cx, 0x12c, 0x11202fff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 = - * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa00d2ef8); - break; - - case 44100: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x18 - */ - cx18_av_write4(cx, 0x108, 0x180e040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x062a1f2 */ - /* xtal * 0xe.3150f90/0x18 = 44100 * 384: 406 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x0062a1f2); - - /* src3/4/6_ctl */ - /* 0x1.6d59 = (4 * xtal/8*2/455) / 44100 */ - cx18_av_write4(cx, 0x900, 0x08016d59); - cx18_av_write4(cx, 0x904, 0x08016d59); - cx18_av_write4(cx, 0x90c, 0x08016d59); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x18 */ - cx18_av_write(cx, 0x127, 0x58); - - /* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */ - cx18_av_write4(cx, 0x12c, 0x112092ff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 = - * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa01d4bf8); - break; - - case 48000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x16 - */ - cx18_av_write4(cx, 0x108, 0x160e040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x05227ad */ - /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x005227ad); - - /* src3/4/6_ctl */ - /* 0x1.4faa = (4 * xtal/8*2/455) / 48000 */ - cx18_av_write4(cx, 0x900, 0x08014faa); - cx18_av_write4(cx, 0x904, 0x08014faa); - cx18_av_write4(cx, 0x90c, 0x08014faa); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ - cx18_av_write(cx, 0x127, 0x56); - - /* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */ - cx18_av_write4(cx, 0x12c, 0x11205fff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x1193f8 = 143999.000 * 8 = - * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa01193f8); - break; - } - } else { - switch (freq) { - case 32000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x30 - */ - cx18_av_write4(cx, 0x108, 0x300d040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x176740c */ - /* xtal * 0xd.bb3a060/0x30 = 32000 * 256: 393 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x0176740c); - - /* src1_ctl */ - /* 0x1.0000 = 32000/32000 */ - cx18_av_write4(cx, 0x8f8, 0x08010000); - - /* src3/4/6_ctl */ - /* 0x2.0000 = 2 * (32000/32000) */ - cx18_av_write4(cx, 0x900, 0x08020000); - cx18_av_write4(cx, 0x904, 0x08020000); - cx18_av_write4(cx, 0x90c, 0x08020000); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x30 */ - cx18_av_write(cx, 0x127, 0x70); - - /* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */ - cx18_av_write4(cx, 0x12c, 0x11201fff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 = - * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa00d2ef8); - break; - - case 44100: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0e, AUX PLL Post Divider = 0x24 - */ - cx18_av_write4(cx, 0x108, 0x240e040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x062a1f2 */ - /* xtal * 0xe.3150f90/0x24 = 44100 * 256: 406 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x0062a1f2); - - /* src1_ctl */ - /* 0x1.60cd = 44100/32000 */ - cx18_av_write4(cx, 0x8f8, 0x080160cd); - - /* src3/4/6_ctl */ - /* 0x1.7385 = 2 * (32000/44100) */ - cx18_av_write4(cx, 0x900, 0x08017385); - cx18_av_write4(cx, 0x904, 0x08017385); - cx18_av_write4(cx, 0x90c, 0x08017385); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x24 */ - cx18_av_write(cx, 0x127, 0x64); - - /* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */ - cx18_av_write4(cx, 0x12c, 0x112061ff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 = - * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa01d4bf8); - break; - - case 48000: - /* - * VID_PLL Integer = 0x0f, VID_PLL Post Divider = 0x04 - * AUX_PLL Integer = 0x0d, AUX PLL Post Divider = 0x20 - */ - cx18_av_write4(cx, 0x108, 0x200d040f); - - /* VID_PLL Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz pre-postdiv*/ - cx18_av_write4(cx, 0x10c, 0x002be2fe); - - /* AUX_PLL Fraction = 0x176740c */ - /* xtal * 0xd.bb3a060/0x20 = 48000 * 256: 393 MHz p-pd*/ - cx18_av_write4(cx, 0x110, 0x0176740c); - - /* src1_ctl */ - /* 0x1.8000 = 48000/32000 */ - cx18_av_write4(cx, 0x8f8, 0x08018000); - - /* src3/4/6_ctl */ - /* 0x1.5555 = 2 * (32000/48000) */ - cx18_av_write4(cx, 0x900, 0x08015555); - cx18_av_write4(cx, 0x904, 0x08015555); - cx18_av_write4(cx, 0x90c, 0x08015555); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x20 */ - cx18_av_write(cx, 0x127, 0x60); - - /* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */ - cx18_av_write4(cx, 0x12c, 0x11203fff); - - /* - * EN_AV_LOCK = 0 - * VID_COUNT = 0x1193f8 = 143999.000 * 8 = - * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8 - */ - cx18_av_write4(cx, 0x128, 0xa01193f8); - break; - } - } - - state->audclk_freq = freq; - - return 0; -} - -void cx18_av_audio_set_path(struct cx18 *cx) -{ - struct cx18_av_state *state = &cx->av_state; - u8 v; - - /* stop microcontroller */ - v = cx18_av_read(cx, 0x803) & ~0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - - /* assert soft reset */ - v = cx18_av_read(cx, 0x810) | 0x01; - cx18_av_write_expect(cx, 0x810, v, v, 0x0f); - - /* Mute everything to prevent the PFFT! */ - cx18_av_write(cx, 0x8d3, 0x1f); - - if (state->aud_input <= CX18_AV_AUDIO_SERIAL2) { - /* Set Path1 to Serial Audio Input */ - cx18_av_write4(cx, 0x8d0, 0x01011012); - - /* The microcontroller should not be started for the - * non-tuner inputs: autodetection is specific for - * TV audio. */ - } else { - /* Set Path1 to Analog Demod Main Channel */ - cx18_av_write4(cx, 0x8d0, 0x1f063870); - } - - set_audclk_freq(cx, state->audclk_freq); - - /* deassert soft reset */ - v = cx18_av_read(cx, 0x810) & ~0x01; - cx18_av_write_expect(cx, 0x810, v, v, 0x0f); - - if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { - /* When the microcontroller detects the - * audio format, it will unmute the lines */ - v = cx18_av_read(cx, 0x803) | 0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - } -} - -static void set_volume(struct cx18 *cx, int volume) -{ - /* First convert the volume to msp3400 values (0-127) */ - int vol = volume >> 9; - /* now scale it up to cx18_av values - * -114dB to -96dB maps to 0 - * this should be 19, but in my testing that was 4dB too loud */ - if (vol <= 23) - vol = 0; - else - vol -= 23; - - /* PATH1_VOLUME */ - cx18_av_write(cx, 0x8d4, 228 - (vol * 2)); -} - -static void set_bass(struct cx18 *cx, int bass) -{ - /* PATH1_EQ_BASS_VOL */ - cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff)); -} - -static void set_treble(struct cx18 *cx, int treble) -{ - /* PATH1_EQ_TREBLE_VOL */ - cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff)); -} - -static void set_balance(struct cx18 *cx, int balance) -{ - int bal = balance >> 8; - if (bal > 0x80) { - /* PATH1_BAL_LEFT */ - cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80); - /* PATH1_BAL_LEVEL */ - cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f); - } else { - /* PATH1_BAL_LEFT */ - cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00); - /* PATH1_BAL_LEVEL */ - cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal); - } -} - -static void set_mute(struct cx18 *cx, int mute) -{ - struct cx18_av_state *state = &cx->av_state; - u8 v; - - if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { - /* Must turn off microcontroller in order to mute sound. - * Not sure if this is the best method, but it does work. - * If the microcontroller is running, then it will undo any - * changes to the mute register. */ - v = cx18_av_read(cx, 0x803); - if (mute) { - /* disable microcontroller */ - v &= ~0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - cx18_av_write(cx, 0x8d3, 0x1f); - } else { - /* enable microcontroller */ - v |= 0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - } - } else { - /* SRC1_MUTE_EN */ - cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00); - } -} - -int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - struct cx18_av_state *state = &cx->av_state; - int retval; - u8 v; - - if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { - v = cx18_av_read(cx, 0x803) & ~0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - cx18_av_write(cx, 0x8d3, 0x1f); - } - v = cx18_av_read(cx, 0x810) | 0x1; - cx18_av_write_expect(cx, 0x810, v, v, 0x0f); - - retval = set_audclk_freq(cx, freq); - - v = cx18_av_read(cx, 0x810) & ~0x1; - cx18_av_write_expect(cx, 0x810, v, v, 0x0f); - if (state->aud_input > CX18_AV_AUDIO_SERIAL2) { - v = cx18_av_read(cx, 0x803) | 0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - } - return retval; -} - -static int cx18_av_audio_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct cx18 *cx = v4l2_get_subdevdata(sd); - - switch (ctrl->id) { - case V4L2_CID_AUDIO_VOLUME: - set_volume(cx, ctrl->val); - break; - case V4L2_CID_AUDIO_BASS: - set_bass(cx, ctrl->val); - break; - case V4L2_CID_AUDIO_TREBLE: - set_treble(cx, ctrl->val); - break; - case V4L2_CID_AUDIO_BALANCE: - set_balance(cx, ctrl->val); - break; - case V4L2_CID_AUDIO_MUTE: - set_mute(cx, ctrl->val); - break; - default: - return -EINVAL; - } - return 0; -} - -const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops = { - .s_ctrl = cx18_av_audio_s_ctrl, -}; diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c deleted file mode 100644 index f164b7f610a..00000000000 --- a/drivers/media/video/cx18/cx18-av-core.c +++ /dev/null @@ -1,1401 +0,0 @@ -/* - * cx18 ADEC audio functions - * - * Derived from cx25840-core.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include <media/v4l2-chip-ident.h> -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-cards.h" - -int cx18_av_write(struct cx18 *cx, u16 addr, u8 value) -{ - u32 reg = 0xc40000 + (addr & ~3); - u32 mask = 0xff; - int shift = (addr & 3) * 8; - u32 x = cx18_read_reg(cx, reg); - - x = (x & ~(mask << shift)) | ((u32)value << shift); - cx18_write_reg(cx, x, reg); - return 0; -} - -int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask) -{ - u32 reg = 0xc40000 + (addr & ~3); - int shift = (addr & 3) * 8; - u32 x = cx18_read_reg(cx, reg); - - x = (x & ~((u32)0xff << shift)) | ((u32)value << shift); - cx18_write_reg_expect(cx, x, reg, - ((u32)eval << shift), ((u32)mask << shift)); - return 0; -} - -int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value) -{ - cx18_write_reg(cx, value, 0xc40000 + addr); - return 0; -} - -int -cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, u32 mask) -{ - cx18_write_reg_expect(cx, value, 0xc40000 + addr, eval, mask); - return 0; -} - -int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value) -{ - cx18_write_reg_noretry(cx, value, 0xc40000 + addr); - return 0; -} - -u8 cx18_av_read(struct cx18 *cx, u16 addr) -{ - u32 x = cx18_read_reg(cx, 0xc40000 + (addr & ~3)); - int shift = (addr & 3) * 8; - - return (x >> shift) & 0xff; -} - -u32 cx18_av_read4(struct cx18 *cx, u16 addr) -{ - return cx18_read_reg(cx, 0xc40000 + addr); -} - -int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask, - u8 or_value) -{ - return cx18_av_write(cx, addr, - (cx18_av_read(cx, addr) & and_mask) | - or_value); -} - -int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask, - u32 or_value) -{ - return cx18_av_write4(cx, addr, - (cx18_av_read4(cx, addr) & and_mask) | - or_value); -} - -static void cx18_av_init(struct cx18 *cx) -{ - /* - * The crystal freq used in calculations in this driver will be - * 28.636360 MHz. - * Aim to run the PLLs' VCOs near 400 MHz to minimze errors. - */ - - /* - * VDCLK Integer = 0x0f, Post Divider = 0x04 - * AIMCLK Integer = 0x0e, Post Divider = 0x16 - */ - cx18_av_write4(cx, CXADEC_PLL_CTRL1, 0x160e040f); - - /* VDCLK Fraction = 0x2be2fe */ - /* xtal * 0xf.15f17f0/4 = 108 MHz: 432 MHz before post divide */ - cx18_av_write4(cx, CXADEC_VID_PLL_FRAC, 0x002be2fe); - - /* AIMCLK Fraction = 0x05227ad */ - /* xtal * 0xe.2913d68/0x16 = 48000 * 384: 406 MHz pre post-div*/ - cx18_av_write4(cx, CXADEC_AUX_PLL_FRAC, 0x005227ad); - - /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x16 */ - cx18_av_write(cx, CXADEC_I2S_MCLK, 0x56); -} - -static void cx18_av_initialize(struct v4l2_subdev *sd) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - int default_volume; - u32 v; - - cx18_av_loadfw(cx); - /* Stop 8051 code execution */ - cx18_av_write4_expect(cx, CXADEC_DL_CTL, 0x03000000, - 0x03000000, 0x13000000); - - /* initallize the PLL by toggling sleep bit */ - v = cx18_av_read4(cx, CXADEC_HOST_REG1); - /* enable sleep mode - register appears to be read only... */ - cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v | 1, v, 0xfffe); - /* disable sleep mode */ - cx18_av_write4_expect(cx, CXADEC_HOST_REG1, v & 0xfffe, - v & 0xfffe, 0xffff); - - /* initialize DLLs */ - v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF; - /* disable FLD */ - cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v); - /* enable FLD */ - cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100); - - v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF; - /* disable FLD */ - cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v); - /* enable FLD */ - cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100); - - /* set analog bias currents. Set Vreg to 1.20V. */ - cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802); - - v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1; - /* enable TUNE_FIL_RST */ - cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, v, v, 0x03009F0F); - /* disable TUNE_FIL_RST */ - cx18_av_write4_expect(cx, CXADEC_AFE_DIAG_CTRL3, - v & 0xFFFFFFFE, v & 0xFFFFFFFE, 0x03009F0F); - - /* enable 656 output */ - cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00); - - /* video output drive strength */ - cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2); - - /* reset video */ - cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000); - cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0); - - /* - * Disable Video Auto-config of the Analog Front End and Video PLL. - * - * Since we only use BT.656 pixel mode, which works for both 525 and 625 - * line systems, it's just easier for us to set registers - * 0x102 (CXADEC_CHIP_CTRL), 0x104-0x106 (CXADEC_AFE_CTRL), - * 0x108-0x109 (CXADEC_PLL_CTRL1), and 0x10c-0x10f (CXADEC_VID_PLL_FRAC) - * ourselves, than to run around cleaning up after the auto-config. - * - * (Note: my CX23418 chip doesn't seem to let the ACFG_DIS bit - * get set to 1, but OTOH, it doesn't seem to do AFE and VID PLL - * autoconfig either.) - * - * As a default, also turn off Dual mode for ADC2 and set ADC2 to CH3. - */ - cx18_av_and_or4(cx, CXADEC_CHIP_CTRL, 0xFFFBFFFF, 0x00120000); - - /* Setup the Video and and Aux/Audio PLLs */ - cx18_av_init(cx); - - /* set video to auto-detect */ - /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */ - /* set the comb notch = 1 */ - cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800); - - /* Enable wtw_en in CRUSH_CTRL (Set bit 22) */ - /* Enable maj_sel in CRUSH_CTRL (Set bit 20) */ - cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000); - - /* Set VGA_TRACK_RANGE to 0x20 */ - cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000); - - /* - * Initial VBI setup - * VIP-1.1, 10 bit mode, enable Raw, disable sliced, - * don't clamp raw samples when codes are in use, 1 byte user D-words, - * IDID0 has line #, RP code V bit transition on VBLANK, data during - * blanking intervals - */ - cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4013252e); - - /* Set the video input. - The setting in MODE_CTRL gets lost when we do the above setup */ - /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */ - /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */ - - /* - * Analog Front End (AFE) - * Default to luma on ch1/ADC1, chroma on ch2/ADC2, SIF on ch3/ADC2 - * bypass_ch[1-3] use filter - * droop_comp_ch[1-3] disable - * clamp_en_ch[1-3] disable - * aud_in_sel ADC2 - * luma_in_sel ADC1 - * chroma_in_sel ADC2 - * clamp_sel_ch[2-3] midcode - * clamp_sel_ch1 video decoder - * vga_sel_ch3 audio decoder - * vga_sel_ch[1-2] video decoder - * half_bw_ch[1-3] disable - * +12db_ch[1-3] disable - */ - cx18_av_and_or4(cx, CXADEC_AFE_CTRL, 0xFF000000, 0x00005D00); - -/* if(dwEnable && dw3DCombAvailable) { */ -/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */ -/* } else { */ -/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */ -/* } */ - cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F); - default_volume = cx18_av_read(cx, 0x8d4); - /* - * Enforce the legacy volume scale mapping limits to avoid - * -ERANGE errors when initializing the volume control - */ - if (default_volume > 228) { - /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */ - default_volume = 228; - cx18_av_write(cx, 0x8d4, 228); - } else if (default_volume < 20) { - /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */ - default_volume = 20; - cx18_av_write(cx, 0x8d4, 20); - } - default_volume = (((228 - default_volume) >> 1) + 23) << 9; - state->volume->cur.val = state->volume->default_value = default_volume; - v4l2_ctrl_handler_setup(&state->hdl); -} - -static int cx18_av_reset(struct v4l2_subdev *sd, u32 val) -{ - cx18_av_initialize(sd); - return 0; -} - -static int cx18_av_load_fw(struct v4l2_subdev *sd) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - - if (!state->is_initialized) { - /* initialize on first use */ - state->is_initialized = 1; - cx18_av_initialize(sd); - } - return 0; -} - -void cx18_av_std_setup(struct cx18 *cx) -{ - struct cx18_av_state *state = &cx->av_state; - struct v4l2_subdev *sd = &state->sd; - v4l2_std_id std = state->std; - - /* - * Video ADC crystal clock to pixel clock SRC decimation ratio - * 28.636360 MHz/13.5 Mpps * 256 = 0x21f.07b - */ - const int src_decimation = 0x21f; - - int hblank, hactive, burst, vblank, vactive, sc; - int vblank656; - int luma_lpf, uv_lpf, comb; - u32 pll_int, pll_frac, pll_post; - - /* datasheet startup, step 8d */ - if (std & ~V4L2_STD_NTSC) - cx18_av_write(cx, 0x49f, 0x11); - else - cx18_av_write(cx, 0x49f, 0x14); - - /* - * Note: At the end of a field, there are 3 sets of half line duration - * (double horizontal rate) pulses: - * - * 5 (625) or 6 (525) half-lines to blank for the vertical retrace - * 5 (625) or 6 (525) vertical sync pulses of half line duration - * 5 (625) or 6 (525) half-lines of equalization pulses - */ - if (std & V4L2_STD_625_50) { - /* - * The following relationships of half line counts should hold: - * 625 = vblank656 + vactive - * 10 = vblank656 - vblank = vsync pulses + equalization pulses - * - * vblank656: half lines after line 625/mid-313 of blanked video - * vblank: half lines, after line 5/317, of blanked video - * vactive: half lines of active video + - * 5 half lines after the end of active video - * - * As far as I can tell: - * vblank656 starts counting from the falling edge of the first - * vsync pulse (start of line 1 or mid-313) - * vblank starts counting from the after the 5 vsync pulses and - * 5 or 4 equalization pulses (start of line 6 or 318) - * - * For 625 line systems the driver will extract VBI information - * from lines 6-23 and lines 318-335 (but the slicer can only - * handle 17 lines, not the 18 in the vblank region). - * In addition, we need vblank656 and vblank to be one whole - * line longer, to cover line 24 and 336, so the SAV/EAV RP - * codes get generated such that the encoder can actually - * extract line 23 & 335 (WSS). We'll lose 1 line in each field - * at the top of the screen. - * - * It appears the 5 half lines that happen after active - * video must be included in vactive (579 instead of 574), - * otherwise the colors get badly displayed in various regions - * of the screen. I guess the chroma comb filter gets confused - * without them (at least when a PVR-350 is the PAL source). - */ - vblank656 = 48; /* lines 1 - 24 & 313 - 336 */ - vblank = 38; /* lines 6 - 24 & 318 - 336 */ - vactive = 579; /* lines 24 - 313 & 337 - 626 */ - - /* - * For a 13.5 Mpps clock and 15,625 Hz line rate, a line is - * is 864 pixels = 720 active + 144 blanking. ITU-R BT.601 - * specifies 12 luma clock periods or ~ 0.9 * 13.5 Mpps after - * the end of active video to start a horizontal line, so that - * leaves 132 pixels of hblank to ignore. - */ - hblank = 132; - hactive = 720; - - /* - * Burst gate delay (for 625 line systems) - * Hsync leading edge to color burst rise = 5.6 us - * Color burst width = 2.25 us - * Gate width = 4 pixel clocks - * (5.6 us + 2.25/2 us) * 13.5 Mpps + 4/2 clocks = 92.79 clocks - */ - burst = 93; - luma_lpf = 2; - if (std & V4L2_STD_PAL) { - uv_lpf = 1; - comb = 0x20; - /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */ - sc = 688700; - } else if (std == V4L2_STD_PAL_Nc) { - uv_lpf = 1; - comb = 0x20; - /* sc = 3582056.25 * src_decimation/28636360 * 2^13 */ - sc = 556422; - } else { /* SECAM */ - uv_lpf = 0; - comb = 0; - /* (fr + fb)/2 = (4406260 + 4250000)/2 = 4328130 */ - /* sc = 4328130 * src_decimation/28636360 * 2^13 */ - sc = 672314; - } - } else { - /* - * The following relationships of half line counts should hold: - * 525 = prevsync + vblank656 + vactive - * 12 = vblank656 - vblank = vsync pulses + equalization pulses - * - * prevsync: 6 half-lines before the vsync pulses - * vblank656: half lines, after line 3/mid-266, of blanked video - * vblank: half lines, after line 9/272, of blanked video - * vactive: half lines of active video - * - * As far as I can tell: - * vblank656 starts counting from the falling edge of the first - * vsync pulse (start of line 4 or mid-266) - * vblank starts counting from the after the 6 vsync pulses and - * 6 or 5 equalization pulses (start of line 10 or 272) - * - * For 525 line systems the driver will extract VBI information - * from lines 10-21 and lines 273-284. - */ - vblank656 = 38; /* lines 4 - 22 & 266 - 284 */ - vblank = 26; /* lines 10 - 22 & 272 - 284 */ - vactive = 481; /* lines 23 - 263 & 285 - 525 */ - - /* - * For a 13.5 Mpps clock and 15,734.26 Hz line rate, a line is - * is 858 pixels = 720 active + 138 blanking. The Hsync leading - * edge should happen 1.2 us * 13.5 Mpps ~= 16 pixels after the - * end of active video, leaving 122 pixels of hblank to ignore - * before active video starts. - */ - hactive = 720; - hblank = 122; - luma_lpf = 1; - uv_lpf = 1; - - /* - * Burst gate delay (for 525 line systems) - * Hsync leading edge to color burst rise = 5.3 us - * Color burst width = 2.5 us - * Gate width = 4 pixel clocks - * (5.3 us + 2.5/2 us) * 13.5 Mpps + 4/2 clocks = 90.425 clocks - */ - if (std == V4L2_STD_PAL_60) { - burst = 90; - luma_lpf = 2; - comb = 0x20; - /* sc = 4433618.75 * src_decimation/28636360 * 2^13 */ - sc = 688700; - } else if (std == V4L2_STD_PAL_M) { - /* The 97 needs to be verified against PAL-M timings */ - burst = 97; - comb = 0x20; - /* sc = 3575611.49 * src_decimation/28636360 * 2^13 */ - sc = 555421; - } else { - burst = 90; - comb = 0x66; - /* sc = 3579545.45.. * src_decimation/28636360 * 2^13 */ - sc = 556032; - } - } - - /* DEBUG: Displays configured PLL frequency */ - pll_int = cx18_av_read(cx, 0x108); - pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff; - pll_post = cx18_av_read(cx, 0x109); - CX18_DEBUG_INFO_DEV(sd, "PLL regs = int: %u, frac: %u, post: %u\n", - pll_int, pll_frac, pll_post); - - if (pll_post) { - int fsc, pll; - u64 tmp; - - pll = (28636360L * ((((u64)pll_int) << 25) + pll_frac)) >> 25; - pll /= pll_post; - CX18_DEBUG_INFO_DEV(sd, "Video PLL = %d.%06d MHz\n", - pll / 1000000, pll % 1000000); - CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n", - pll / 8000000, (pll / 8) % 1000000); - - CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio " - "= %d.%03d\n", src_decimation / 256, - ((src_decimation % 256) * 1000) / 256); - - tmp = 28636360 * (u64) sc; - do_div(tmp, src_decimation); - fsc = tmp >> 13; - CX18_DEBUG_INFO_DEV(sd, - "Chroma sub-carrier initial freq = %d.%06d " - "MHz\n", fsc / 1000000, fsc % 1000000); - - CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, " - "vactive %i, vblank656 %i, src_dec %i, " - "burst 0x%02x, luma_lpf %i, uv_lpf %i, " - "comb 0x%02x, sc 0x%06x\n", - hblank, hactive, vblank, vactive, vblank656, - src_decimation, burst, luma_lpf, uv_lpf, - comb, sc); - } - - /* Sets horizontal blanking delay and active lines */ - cx18_av_write(cx, 0x470, hblank); - cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) | - (hactive << 4))); - cx18_av_write(cx, 0x472, hactive >> 4); - - /* Sets burst gate delay */ - cx18_av_write(cx, 0x473, burst); - - /* Sets vertical blanking delay and active duration */ - cx18_av_write(cx, 0x474, vblank); - cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) | - (vactive << 4))); - cx18_av_write(cx, 0x476, vactive >> 4); - cx18_av_write(cx, 0x477, vblank656); - - /* Sets src decimation rate */ - cx18_av_write(cx, 0x478, 0xff & src_decimation); - cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8)); - - /* Sets Luma and UV Low pass filters */ - cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30)); - - /* Enables comb filters */ - cx18_av_write(cx, 0x47b, comb); - - /* Sets SC Step*/ - cx18_av_write(cx, 0x47c, sc); - cx18_av_write(cx, 0x47d, 0xff & sc >> 8); - cx18_av_write(cx, 0x47e, 0xff & sc >> 16); - - if (std & V4L2_STD_625_50) { - state->slicer_line_delay = 1; - state->slicer_line_offset = (6 + state->slicer_line_delay - 2); - } else { - state->slicer_line_delay = 0; - state->slicer_line_offset = (10 + state->slicer_line_delay - 2); - } - cx18_av_write(cx, 0x47f, state->slicer_line_delay); -} - -static void input_change(struct cx18 *cx) -{ - struct cx18_av_state *state = &cx->av_state; - v4l2_std_id std = state->std; - u8 v; - - /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */ - cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11); - cx18_av_and_or(cx, 0x401, ~0x60, 0); - cx18_av_and_or(cx, 0x401, ~0x60, 0x60); - - if (std & V4L2_STD_525_60) { - if (std == V4L2_STD_NTSC_M_JP) { - /* Japan uses EIAJ audio standard */ - cx18_av_write_expect(cx, 0x808, 0xf7, 0xf7, 0xff); - cx18_av_write_expect(cx, 0x80b, 0x02, 0x02, 0x3f); - } else if (std == V4L2_STD_NTSC_M_KR) { - /* South Korea uses A2 audio standard */ - cx18_av_write_expect(cx, 0x808, 0xf8, 0xf8, 0xff); - cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); - } else { - /* Others use the BTSC audio standard */ - cx18_av_write_expect(cx, 0x808, 0xf6, 0xf6, 0xff); - cx18_av_write_expect(cx, 0x80b, 0x01, 0x01, 0x3f); - } - } else if (std & V4L2_STD_PAL) { - /* Follow tuner change procedure for PAL */ - cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff); - cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); - } else if (std & V4L2_STD_SECAM) { - /* Select autodetect for SECAM */ - cx18_av_write_expect(cx, 0x808, 0xff, 0xff, 0xff); - cx18_av_write_expect(cx, 0x80b, 0x03, 0x03, 0x3f); - } - - v = cx18_av_read(cx, 0x803); - if (v & 0x10) { - /* restart audio decoder microcontroller */ - v &= ~0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - v |= 0x10; - cx18_av_write_expect(cx, 0x803, v, v, 0x1f); - } -} - -static int cx18_av_s_frequency(struct v4l2_subdev *sd, - struct v4l2_frequency *freq) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - input_change(cx); - return 0; -} - -static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input, - enum cx18_av_audio_input aud_input) -{ - struct cx18_av_state *state = &cx->av_state; - struct v4l2_subdev *sd = &state->sd; - - enum analog_signal_type { - NONE, CVBS, Y, C, SIF, Pb, Pr - } ch[3] = {NONE, NONE, NONE}; - - u8 afe_mux_cfg; - u8 adc2_cfg; - u8 input_mode; - u32 afe_cfg; - int i; - - CX18_DEBUG_INFO_DEV(sd, "decoder set video input %d, audio input %d\n", - vid_input, aud_input); - - if (vid_input >= CX18_AV_COMPOSITE1 && - vid_input <= CX18_AV_COMPOSITE8) { - afe_mux_cfg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1); - ch[0] = CVBS; - input_mode = 0x0; - } else if (vid_input >= CX18_AV_COMPONENT_LUMA1) { - int luma = vid_input & 0xf000; - int r_chroma = vid_input & 0xf0000; - int b_chroma = vid_input & 0xf00000; - - if ((vid_input & ~0xfff000) || - luma < CX18_AV_COMPONENT_LUMA1 || - luma > CX18_AV_COMPONENT_LUMA8 || - r_chroma < CX18_AV_COMPONENT_R_CHROMA4 || - r_chroma > CX18_AV_COMPONENT_R_CHROMA6 || - b_chroma < CX18_AV_COMPONENT_B_CHROMA7 || - b_chroma > CX18_AV_COMPONENT_B_CHROMA8) { - CX18_ERR_DEV(sd, "0x%06x is not a valid video input!\n", - vid_input); - return -EINVAL; - } - afe_mux_cfg = (luma - CX18_AV_COMPONENT_LUMA1) >> 12; - ch[0] = Y; - afe_mux_cfg |= (r_chroma - CX18_AV_COMPONENT_R_CHROMA4) >> 12; - ch[1] = Pr; - afe_mux_cfg |= (b_chroma - CX18_AV_COMPONENT_B_CHROMA7) >> 14; - ch[2] = Pb; - input_mode = 0x6; - } else { - int luma = vid_input & 0xf0; - int chroma = vid_input & 0xf00; - - if ((vid_input & ~0xff0) || - luma < CX18_AV_SVIDEO_LUMA1 || - luma > CX18_AV_SVIDEO_LUMA8 || - chroma < CX18_AV_SVIDEO_CHROMA4 || - chroma > CX18_AV_SVIDEO_CHROMA8) { - CX18_ERR_DEV(sd, "0x%06x is not a valid video input!\n", - vid_input); - return -EINVAL; - } - afe_mux_cfg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4); - ch[0] = Y; - if (chroma >= CX18_AV_SVIDEO_CHROMA7) { - afe_mux_cfg &= 0x3f; - afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2; - ch[2] = C; - } else { - afe_mux_cfg &= 0xcf; - afe_mux_cfg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4; - ch[1] = C; - } - input_mode = 0x2; - } - - switch (aud_input) { - case CX18_AV_AUDIO_SERIAL1: - case CX18_AV_AUDIO_SERIAL2: - /* do nothing, use serial audio input */ - break; - case CX18_AV_AUDIO4: - afe_mux_cfg &= ~0x30; - ch[1] = SIF; - break; - case CX18_AV_AUDIO5: - afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x10; - ch[1] = SIF; - break; - case CX18_AV_AUDIO6: - afe_mux_cfg = (afe_mux_cfg & ~0x30) | 0x20; - ch[1] = SIF; - break; - case CX18_AV_AUDIO7: - afe_mux_cfg &= ~0xc0; - ch[2] = SIF; - break; - case CX18_AV_AUDIO8: - afe_mux_cfg = (afe_mux_cfg & ~0xc0) | 0x40; - ch[2] = SIF; - break; - - default: - CX18_ERR_DEV(sd, "0x%04x is not a valid audio input!\n", - aud_input); - return -EINVAL; - } - - /* Set up analog front end multiplexers */ - cx18_av_write_expect(cx, 0x103, afe_mux_cfg, afe_mux_cfg, 0xf7); - /* Set INPUT_MODE to Composite, S-Video, or Component */ - cx18_av_and_or(cx, 0x401, ~0x6, input_mode); - - /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */ - adc2_cfg = cx18_av_read(cx, 0x102); - if (ch[2] == NONE) - adc2_cfg &= ~0x2; /* No sig on CH3, set ADC2 to CH2 for input */ - else - adc2_cfg |= 0x2; /* Signal on CH3, set ADC2 to CH3 for input */ - - /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */ - if (ch[1] != NONE && ch[2] != NONE) - adc2_cfg |= 0x4; /* Set dual mode */ - else - adc2_cfg &= ~0x4; /* Clear dual mode */ - cx18_av_write_expect(cx, 0x102, adc2_cfg, adc2_cfg, 0x17); - - /* Configure the analog front end */ - afe_cfg = cx18_av_read4(cx, CXADEC_AFE_CTRL); - afe_cfg &= 0xff000000; - afe_cfg |= 0x00005000; /* CHROMA_IN, AUD_IN: ADC2; LUMA_IN: ADC1 */ - if (ch[1] != NONE && ch[2] != NONE) - afe_cfg |= 0x00000030; /* half_bw_ch[2-3] since in dual mode */ - - for (i = 0; i < 3; i++) { - switch (ch[i]) { - default: - case NONE: - /* CLAMP_SEL = Fixed to midcode clamp level */ - afe_cfg |= (0x00000200 << i); - break; - case CVBS: - case Y: - if (i > 0) - afe_cfg |= 0x00002000; /* LUMA_IN_SEL: ADC2 */ - break; - case C: - case Pb: - case Pr: - /* CLAMP_SEL = Fixed to midcode clamp level */ - afe_cfg |= (0x00000200 << i); - if (i == 0 && ch[i] == C) - afe_cfg &= ~0x00001000; /* CHROMA_IN_SEL ADC1 */ - break; - case SIF: - /* - * VGA_GAIN_SEL = Audio Decoder - * CLAMP_SEL = Fixed to midcode clamp level - */ - afe_cfg |= (0x00000240 << i); - if (i == 0) - afe_cfg &= ~0x00004000; /* AUD_IN_SEL ADC1 */ - break; - } - } - - cx18_av_write4(cx, CXADEC_AFE_CTRL, afe_cfg); - - state->vid_input = vid_input; - state->aud_input = aud_input; - cx18_av_audio_set_path(cx); - input_change(cx); - return 0; -} - -static int cx18_av_s_video_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - return set_input(cx, input, state->aud_input); -} - -static int cx18_av_s_audio_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - return set_input(cx, state->vid_input, input); -} - -static int cx18_av_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - u8 vpres; - u8 mode; - int val = 0; - - if (state->radio) - return 0; - - vpres = cx18_av_read(cx, 0x40e) & 0x20; - vt->signal = vpres ? 0xffff : 0x0; - - vt->capability |= - V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | - V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; - - mode = cx18_av_read(cx, 0x804); - - /* get rxsubchans and audmode */ - if ((mode & 0xf) == 1) - val |= V4L2_TUNER_SUB_STEREO; - else - val |= V4L2_TUNER_SUB_MONO; - - if (mode == 2 || mode == 4) - val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - - if (mode & 0x10) - val |= V4L2_TUNER_SUB_SAP; - - vt->rxsubchans = val; - vt->audmode = state->audmode; - return 0; -} - -static int cx18_av_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - u8 v; - - if (state->radio) - return 0; - - v = cx18_av_read(cx, 0x809); - v &= ~0xf; - - switch (vt->audmode) { - case V4L2_TUNER_MODE_MONO: - /* mono -> mono - stereo -> mono - bilingual -> lang1 */ - break; - case V4L2_TUNER_MODE_STEREO: - case V4L2_TUNER_MODE_LANG1: - /* mono -> mono - stereo -> stereo - bilingual -> lang1 */ - v |= 0x4; - break; - case V4L2_TUNER_MODE_LANG1_LANG2: - /* mono -> mono - stereo -> stereo - bilingual -> lang1/lang2 */ - v |= 0x7; - break; - case V4L2_TUNER_MODE_LANG2: - /* mono -> mono - stereo -> stereo - bilingual -> lang2 */ - v |= 0x1; - break; - default: - return -EINVAL; - } - cx18_av_write_expect(cx, 0x809, v, v, 0xff); - state->audmode = vt->audmode; - return 0; -} - -static int cx18_av_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - - u8 fmt = 0; /* zero is autodetect */ - u8 pal_m = 0; - - if (state->radio == 0 && state->std == norm) - return 0; - - state->radio = 0; - state->std = norm; - - /* First tests should be against specific std */ - if (state->std == V4L2_STD_NTSC_M_JP) { - fmt = 0x2; - } else if (state->std == V4L2_STD_NTSC_443) { - fmt = 0x3; - } else if (state->std == V4L2_STD_PAL_M) { - pal_m = 1; - fmt = 0x5; - } else if (state->std == V4L2_STD_PAL_N) { - fmt = 0x6; - } else if (state->std == V4L2_STD_PAL_Nc) { - fmt = 0x7; - } else if (state->std == V4L2_STD_PAL_60) { - fmt = 0x8; - } else { - /* Then, test against generic ones */ - if (state->std & V4L2_STD_NTSC) - fmt = 0x1; - else if (state->std & V4L2_STD_PAL) - fmt = 0x4; - else if (state->std & V4L2_STD_SECAM) - fmt = 0xc; - } - - CX18_DEBUG_INFO_DEV(sd, "changing video std to fmt %i\n", fmt); - - /* Follow step 9 of section 3.16 in the cx18_av datasheet. - Without this PAL may display a vertical ghosting effect. - This happens for example with the Yuan MPC622. */ - if (fmt >= 4 && fmt < 8) { - /* Set format to NTSC-M */ - cx18_av_and_or(cx, 0x400, ~0xf, 1); - /* Turn off LCOMB */ - cx18_av_and_or(cx, 0x47b, ~6, 0); - } - cx18_av_and_or(cx, 0x400, ~0x2f, fmt | 0x20); - cx18_av_and_or(cx, 0x403, ~0x3, pal_m); - cx18_av_std_setup(cx); - input_change(cx); - return 0; -} - -static int cx18_av_s_radio(struct v4l2_subdev *sd) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - state->radio = 1; - return 0; -} - -static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct v4l2_subdev *sd = to_sd(ctrl); - struct cx18 *cx = v4l2_get_subdevdata(sd); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - cx18_av_write(cx, 0x414, ctrl->val - 128); - break; - - case V4L2_CID_CONTRAST: - cx18_av_write(cx, 0x415, ctrl->val << 1); - break; - - case V4L2_CID_SATURATION: - cx18_av_write(cx, 0x420, ctrl->val << 1); - cx18_av_write(cx, 0x421, ctrl->val << 1); - break; - - case V4L2_CID_HUE: - cx18_av_write(cx, 0x422, ctrl->val); - break; - - default: - return -EINVAL; - } - return 0; -} - -static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - struct cx18 *cx = v4l2_get_subdevdata(sd); - int HSC, VSC, Vsrc, Hsrc, filter, Vlines; - int is_50Hz = !(state->std & V4L2_STD_525_60); - - if (fmt->code != V4L2_MBUS_FMT_FIXED) - return -EINVAL; - - fmt->field = V4L2_FIELD_INTERLACED; - fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - - Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4; - Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4; - - Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4; - Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4; - - /* - * This adjustment reflects the excess of vactive, set in - * cx18_av_std_setup(), above standard values: - * - * 480 + 1 for 60 Hz systems - * 576 + 3 for 50 Hz systems - */ - Vlines = fmt->height + (is_50Hz ? 3 : 1); - - /* - * Invalid height and width scaling requests are: - * 1. width less than 1/16 of the source width - * 2. width greater than the source width - * 3. height less than 1/8 of the source height - * 4. height greater than the source height - */ - if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) || - (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) { - CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n", - fmt->width, fmt->height); - return -ERANGE; - } - - HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20); - VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9)); - VSC &= 0x1fff; - - if (fmt->width >= 385) - filter = 0; - else if (fmt->width > 192) - filter = 1; - else if (fmt->width > 96) - filter = 2; - else - filter = 3; - - CX18_DEBUG_INFO_DEV(sd, - "decoder set size %dx%d -> scale %ux%u\n", - fmt->width, fmt->height, HSC, VSC); - - /* HSCALE=HSC */ - cx18_av_write(cx, 0x418, HSC & 0xff); - cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff); - cx18_av_write(cx, 0x41a, HSC >> 16); - /* VSCALE=VSC */ - cx18_av_write(cx, 0x41c, VSC & 0xff); - cx18_av_write(cx, 0x41d, VSC >> 8); - /* VS_INTRLACE=1 VFILT=filter */ - cx18_av_write(cx, 0x41e, 0x8 | filter); - return 0; -} - -static int cx18_av_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - CX18_DEBUG_INFO_DEV(sd, "%s output\n", enable ? "enable" : "disable"); - if (enable) { - cx18_av_write(cx, 0x115, 0x8c); - cx18_av_write(cx, 0x116, 0x07); - } else { - cx18_av_write(cx, 0x115, 0x00); - cx18_av_write(cx, 0x116, 0x00); - } - return 0; -} - -static void log_video_status(struct cx18 *cx) -{ - static const char *const fmt_strs[] = { - "0x0", - "NTSC-M", "NTSC-J", "NTSC-4.43", - "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60", - "0x9", "0xA", "0xB", - "SECAM", - "0xD", "0xE", "0xF" - }; - - struct cx18_av_state *state = &cx->av_state; - struct v4l2_subdev *sd = &state->sd; - u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf; - u8 gen_stat1 = cx18_av_read(cx, 0x40d); - u8 gen_stat2 = cx18_av_read(cx, 0x40e); - int vid_input = state->vid_input; - - CX18_INFO_DEV(sd, "Video signal: %spresent\n", - (gen_stat2 & 0x20) ? "" : "not "); - CX18_INFO_DEV(sd, "Detected format: %s\n", - fmt_strs[gen_stat1 & 0xf]); - - CX18_INFO_DEV(sd, "Specified standard: %s\n", - vidfmt_sel ? fmt_strs[vidfmt_sel] - : "automatic detection"); - - if (vid_input >= CX18_AV_COMPOSITE1 && - vid_input <= CX18_AV_COMPOSITE8) { - CX18_INFO_DEV(sd, "Specified video input: Composite %d\n", - vid_input - CX18_AV_COMPOSITE1 + 1); - } else { - CX18_INFO_DEV(sd, "Specified video input: " - "S-Video (Luma In%d, Chroma In%d)\n", - (vid_input & 0xf0) >> 4, - (vid_input & 0xf00) >> 8); - } - - CX18_INFO_DEV(sd, "Specified audioclock freq: %d Hz\n", - state->audclk_freq); -} - -static void log_audio_status(struct cx18 *cx) -{ - struct cx18_av_state *state = &cx->av_state; - struct v4l2_subdev *sd = &state->sd; - u8 download_ctl = cx18_av_read(cx, 0x803); - u8 mod_det_stat0 = cx18_av_read(cx, 0x804); - u8 mod_det_stat1 = cx18_av_read(cx, 0x805); - u8 audio_config = cx18_av_read(cx, 0x808); - u8 pref_mode = cx18_av_read(cx, 0x809); - u8 afc0 = cx18_av_read(cx, 0x80b); - u8 mute_ctl = cx18_av_read(cx, 0x8d3); - int aud_input = state->aud_input; - char *p; - - switch (mod_det_stat0) { - case 0x00: p = "mono"; break; - case 0x01: p = "stereo"; break; - case 0x02: p = "dual"; break; - case 0x04: p = "tri"; break; - case 0x10: p = "mono with SAP"; break; - case 0x11: p = "stereo with SAP"; break; - case 0x12: p = "dual with SAP"; break; - case 0x14: p = "tri with SAP"; break; - case 0xfe: p = "forced mode"; break; - default: p = "not defined"; break; - } - CX18_INFO_DEV(sd, "Detected audio mode: %s\n", p); - - switch (mod_det_stat1) { - case 0x00: p = "not defined"; break; - case 0x01: p = "EIAJ"; break; - case 0x02: p = "A2-M"; break; - case 0x03: p = "A2-BG"; break; - case 0x04: p = "A2-DK1"; break; - case 0x05: p = "A2-DK2"; break; - case 0x06: p = "A2-DK3"; break; - case 0x07: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x08: p = "AM-L"; break; - case 0x09: p = "NICAM-BG"; break; - case 0x0a: p = "NICAM-DK"; break; - case 0x0b: p = "NICAM-I"; break; - case 0x0c: p = "NICAM-L"; break; - case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break; - case 0x0e: p = "IF FM Radio"; break; - case 0x0f: p = "BTSC"; break; - case 0x10: p = "detected chrominance"; break; - case 0xfd: p = "unknown audio standard"; break; - case 0xfe: p = "forced audio standard"; break; - case 0xff: p = "no detected audio standard"; break; - default: p = "not defined"; break; - } - CX18_INFO_DEV(sd, "Detected audio standard: %s\n", p); - CX18_INFO_DEV(sd, "Audio muted: %s\n", - (mute_ctl & 0x2) ? "yes" : "no"); - CX18_INFO_DEV(sd, "Audio microcontroller: %s\n", - (download_ctl & 0x10) ? "running" : "stopped"); - - switch (audio_config >> 4) { - case 0x00: p = "undefined"; break; - case 0x01: p = "BTSC"; break; - case 0x02: p = "EIAJ"; break; - case 0x03: p = "A2-M"; break; - case 0x04: p = "A2-BG"; break; - case 0x05: p = "A2-DK1"; break; - case 0x06: p = "A2-DK2"; break; - case 0x07: p = "A2-DK3"; break; - case 0x08: p = "A1 (6.0 MHz FM Mono)"; break; - case 0x09: p = "AM-L"; break; - case 0x0a: p = "NICAM-BG"; break; - case 0x0b: p = "NICAM-DK"; break; - case 0x0c: p = "NICAM-I"; break; - case 0x0d: p = "NICAM-L"; break; - case 0x0e: p = "FM radio"; break; - case 0x0f: p = "automatic detection"; break; - default: p = "undefined"; break; - } - CX18_INFO_DEV(sd, "Configured audio standard: %s\n", p); - - if ((audio_config >> 4) < 0xF) { - switch (audio_config & 0xF) { - case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break; - case 0x01: p = "MONO2 (LANGUAGE B)"; break; - case 0x02: p = "MONO3 (STEREO forced MONO)"; break; - case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break; - case 0x04: p = "STEREO"; break; - case 0x05: p = "DUAL1 (AC)"; break; - case 0x06: p = "DUAL2 (BC)"; break; - case 0x07: p = "DUAL3 (AB)"; break; - default: p = "undefined"; - } - CX18_INFO_DEV(sd, "Configured audio mode: %s\n", p); - } else { - switch (audio_config & 0xF) { - case 0x00: p = "BG"; break; - case 0x01: p = "DK1"; break; - case 0x02: p = "DK2"; break; - case 0x03: p = "DK3"; break; - case 0x04: p = "I"; break; - case 0x05: p = "L"; break; - case 0x06: p = "BTSC"; break; - case 0x07: p = "EIAJ"; break; - case 0x08: p = "A2-M"; break; - case 0x09: p = "FM Radio (4.5 MHz)"; break; - case 0x0a: p = "FM Radio (5.5 MHz)"; break; - case 0x0b: p = "S-Video"; break; - case 0x0f: p = "automatic standard and mode detection"; break; - default: p = "undefined"; break; - } - CX18_INFO_DEV(sd, "Configured audio system: %s\n", p); - } - - if (aud_input) - CX18_INFO_DEV(sd, "Specified audio input: Tuner (In%d)\n", - aud_input); - else - CX18_INFO_DEV(sd, "Specified audio input: External\n"); - - switch (pref_mode & 0xf) { - case 0: p = "mono/language A"; break; - case 1: p = "language B"; break; - case 2: p = "language C"; break; - case 3: p = "analog fallback"; break; - case 4: p = "stereo"; break; - case 5: p = "language AC"; break; - case 6: p = "language BC"; break; - case 7: p = "language AB"; break; - default: p = "undefined"; break; - } - CX18_INFO_DEV(sd, "Preferred audio mode: %s\n", p); - - if ((audio_config & 0xf) == 0xf) { - switch ((afc0 >> 3) & 0x1) { - case 0: p = "system DK"; break; - case 1: p = "system L"; break; - } - CX18_INFO_DEV(sd, "Selected 65 MHz format: %s\n", p); - - switch (afc0 & 0x7) { - case 0: p = "Chroma"; break; - case 1: p = "BTSC"; break; - case 2: p = "EIAJ"; break; - case 3: p = "A2-M"; break; - case 4: p = "autodetect"; break; - default: p = "undefined"; break; - } - CX18_INFO_DEV(sd, "Selected 45 MHz format: %s\n", p); - } -} - -static int cx18_av_log_status(struct v4l2_subdev *sd) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - log_video_status(cx); - log_audio_status(cx); - return 0; -} - -static inline int cx18_av_dbg_match(const struct v4l2_dbg_match *match) -{ - return match->type == V4L2_CHIP_MATCH_HOST && match->addr == 1; -} - -static int cx18_av_g_chip_ident(struct v4l2_subdev *sd, - struct v4l2_dbg_chip_ident *chip) -{ - struct cx18_av_state *state = to_cx18_av_state(sd); - - if (cx18_av_dbg_match(&chip->match)) { - chip->ident = state->id; - chip->revision = state->rev; - } - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int cx18_av_g_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - if (!cx18_av_dbg_match(®->match)) - return -EINVAL; - if ((reg->reg & 0x3) != 0) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - reg->size = 4; - reg->val = cx18_av_read4(cx, reg->reg & 0x00000ffc); - return 0; -} - -static int cx18_av_s_register(struct v4l2_subdev *sd, - struct v4l2_dbg_register *reg) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - if (!cx18_av_dbg_match(®->match)) - return -EINVAL; - if ((reg->reg & 0x3) != 0) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - cx18_av_write4(cx, reg->reg & 0x00000ffc, reg->val); - return 0; -} -#endif - -static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = { - .s_ctrl = cx18_av_s_ctrl, -}; - -static const struct v4l2_subdev_core_ops cx18_av_general_ops = { - .g_chip_ident = cx18_av_g_chip_ident, - .log_status = cx18_av_log_status, - .load_fw = cx18_av_load_fw, - .reset = cx18_av_reset, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, - .s_std = cx18_av_s_std, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .g_register = cx18_av_g_register, - .s_register = cx18_av_s_register, -#endif -}; - -static const struct v4l2_subdev_tuner_ops cx18_av_tuner_ops = { - .s_radio = cx18_av_s_radio, - .s_frequency = cx18_av_s_frequency, - .g_tuner = cx18_av_g_tuner, - .s_tuner = cx18_av_s_tuner, -}; - -static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = { - .s_clock_freq = cx18_av_s_clock_freq, - .s_routing = cx18_av_s_audio_routing, -}; - -static const struct v4l2_subdev_video_ops cx18_av_video_ops = { - .s_routing = cx18_av_s_video_routing, - .s_stream = cx18_av_s_stream, - .s_mbus_fmt = cx18_av_s_mbus_fmt, -}; - -static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = { - .decode_vbi_line = cx18_av_decode_vbi_line, - .g_sliced_fmt = cx18_av_g_sliced_fmt, - .s_sliced_fmt = cx18_av_s_sliced_fmt, - .s_raw_fmt = cx18_av_s_raw_fmt, -}; - -static const struct v4l2_subdev_ops cx18_av_ops = { - .core = &cx18_av_general_ops, - .tuner = &cx18_av_tuner_ops, - .audio = &cx18_av_audio_ops, - .video = &cx18_av_video_ops, - .vbi = &cx18_av_vbi_ops, -}; - -int cx18_av_probe(struct cx18 *cx) -{ - struct cx18_av_state *state = &cx->av_state; - struct v4l2_subdev *sd; - int err; - - state->rev = cx18_av_read4(cx, CXADEC_CHIP_CTRL) & 0xffff; - state->id = ((state->rev >> 4) == CXADEC_CHIP_TYPE_MAKO) - ? V4L2_IDENT_CX23418_843 : V4L2_IDENT_UNKNOWN; - - state->vid_input = CX18_AV_COMPOSITE7; - state->aud_input = CX18_AV_AUDIO8; - state->audclk_freq = 48000; - state->audmode = V4L2_TUNER_MODE_LANG1; - state->slicer_line_delay = 0; - state->slicer_line_offset = (10 + state->slicer_line_delay - 2); - - sd = &state->sd; - v4l2_subdev_init(sd, &cx18_av_ops); - v4l2_set_subdevdata(sd, cx); - snprintf(sd->name, sizeof(sd->name), - "%s %03x", cx->v4l2_dev.name, (state->rev >> 4)); - sd->grp_id = CX18_HW_418_AV; - v4l2_ctrl_handler_init(&state->hdl, 9); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, - V4L2_CID_CONTRAST, 0, 127, 1, 64); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, - V4L2_CID_SATURATION, 0, 127, 1, 64); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - - state->volume = v4l2_ctrl_new_std(&state->hdl, - &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME, - 0, 65535, 65535 / 100, 0); - v4l2_ctrl_new_std(&state->hdl, - &cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE, - 0, 1, 1, 0); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, - V4L2_CID_AUDIO_BALANCE, - 0, 65535, 65535 / 100, 32768); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, - V4L2_CID_AUDIO_BASS, - 0, 65535, 65535 / 100, 32768); - v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops, - V4L2_CID_AUDIO_TREBLE, - 0, 65535, 65535 / 100, 32768); - sd->ctrl_handler = &state->hdl; - if (state->hdl.error) { - int err = state->hdl.error; - - v4l2_ctrl_handler_free(&state->hdl); - return err; - } - err = v4l2_device_register_subdev(&cx->v4l2_dev, sd); - if (err) - v4l2_ctrl_handler_free(&state->hdl); - else - cx18_av_init(cx); - return err; -} diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h deleted file mode 100644 index e9c69d9c9e4..00000000000 --- a/drivers/media/video/cx18/cx18-av-core.h +++ /dev/null @@ -1,391 +0,0 @@ -/* - * cx18 ADEC header - * - * Derived from cx25840-core.h - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#ifndef _CX18_AV_CORE_H_ -#define _CX18_AV_CORE_H_ - -#include <media/v4l2-device.h> -#include <media/v4l2-ctrls.h> - -struct cx18; - -enum cx18_av_video_input { - /* Composite video inputs In1-In8 */ - CX18_AV_COMPOSITE1 = 1, - CX18_AV_COMPOSITE2, - CX18_AV_COMPOSITE3, - CX18_AV_COMPOSITE4, - CX18_AV_COMPOSITE5, - CX18_AV_COMPOSITE6, - CX18_AV_COMPOSITE7, - CX18_AV_COMPOSITE8, - - /* S-Video inputs consist of one luma input (In1-In8) ORed with one - chroma input (In5-In8) */ - CX18_AV_SVIDEO_LUMA1 = 0x10, - CX18_AV_SVIDEO_LUMA2 = 0x20, - CX18_AV_SVIDEO_LUMA3 = 0x30, - CX18_AV_SVIDEO_LUMA4 = 0x40, - CX18_AV_SVIDEO_LUMA5 = 0x50, - CX18_AV_SVIDEO_LUMA6 = 0x60, - CX18_AV_SVIDEO_LUMA7 = 0x70, - CX18_AV_SVIDEO_LUMA8 = 0x80, - CX18_AV_SVIDEO_CHROMA4 = 0x400, - CX18_AV_SVIDEO_CHROMA5 = 0x500, - CX18_AV_SVIDEO_CHROMA6 = 0x600, - CX18_AV_SVIDEO_CHROMA7 = 0x700, - CX18_AV_SVIDEO_CHROMA8 = 0x800, - - /* S-Video aliases for common luma/chroma combinations */ - CX18_AV_SVIDEO1 = 0x510, - CX18_AV_SVIDEO2 = 0x620, - CX18_AV_SVIDEO3 = 0x730, - CX18_AV_SVIDEO4 = 0x840, - - /* Component Video inputs consist of one luma input (In1-In8) ORed - with a red chroma (In4-In6) and blue chroma input (In7-In8) */ - CX18_AV_COMPONENT_LUMA1 = 0x1000, - CX18_AV_COMPONENT_LUMA2 = 0x2000, - CX18_AV_COMPONENT_LUMA3 = 0x3000, - CX18_AV_COMPONENT_LUMA4 = 0x4000, - CX18_AV_COMPONENT_LUMA5 = 0x5000, - CX18_AV_COMPONENT_LUMA6 = 0x6000, - CX18_AV_COMPONENT_LUMA7 = 0x7000, - CX18_AV_COMPONENT_LUMA8 = 0x8000, - CX18_AV_COMPONENT_R_CHROMA4 = 0x40000, - CX18_AV_COMPONENT_R_CHROMA5 = 0x50000, - CX18_AV_COMPONENT_R_CHROMA6 = 0x60000, - CX18_AV_COMPONENT_B_CHROMA7 = 0x700000, - CX18_AV_COMPONENT_B_CHROMA8 = 0x800000, - - /* Component Video aliases for common combinations */ - CX18_AV_COMPONENT1 = 0x861000, -}; - -enum cx18_av_audio_input { - /* Audio inputs: serial or In4-In8 */ - CX18_AV_AUDIO_SERIAL1, - CX18_AV_AUDIO_SERIAL2, - CX18_AV_AUDIO4 = 4, - CX18_AV_AUDIO5, - CX18_AV_AUDIO6, - CX18_AV_AUDIO7, - CX18_AV_AUDIO8, -}; - -struct cx18_av_state { - struct v4l2_subdev sd; - struct v4l2_ctrl_handler hdl; - struct v4l2_ctrl *volume; - int radio; - v4l2_std_id std; - enum cx18_av_video_input vid_input; - enum cx18_av_audio_input aud_input; - u32 audclk_freq; - int audmode; - u32 id; - u32 rev; - int is_initialized; - - /* - * The VBI slicer starts operating and counting lines, beginning at - * slicer line count of 1, at D lines after the deassertion of VRESET. - * This staring field line, S, is 6 (& 319) or 10 (& 273) for 625 or 525 - * line systems respectively. Sliced ancillary data captured on VBI - * slicer line M is inserted after the VBI slicer is done with line M, - * when VBI slicer line count is N = M+1. Thus when the VBI slicer - * reports a VBI slicer line number with ancillary data, the IDID0 byte - * indicates VBI slicer line N. The actual field line that the captured - * data comes from is - * - * L = M+(S+D-1) = N-1+(S+D-1) = N + (S+D-2). - * - * L is the line in the field, not frame, from which the VBI data came. - * N is the line reported by the slicer in the ancillary data. - * D is the slicer_line_delay value programmed into register 0x47f. - * S is 6 for 625 line systems or 10 for 525 line systems - * (S+D-2) is the slicer_line_offset used to convert slicer reported - * line counts to actual field lines. - */ - int slicer_line_delay; - int slicer_line_offset; -}; - - -/* Registers */ -#define CXADEC_CHIP_TYPE_TIGER 0x837 -#define CXADEC_CHIP_TYPE_MAKO 0x843 - -#define CXADEC_HOST_REG1 0x000 -#define CXADEC_HOST_REG2 0x001 - -#define CXADEC_CHIP_CTRL 0x100 -#define CXADEC_AFE_CTRL 0x104 -#define CXADEC_PLL_CTRL1 0x108 -#define CXADEC_VID_PLL_FRAC 0x10C -#define CXADEC_AUX_PLL_FRAC 0x110 -#define CXADEC_PIN_CTRL1 0x114 -#define CXADEC_PIN_CTRL2 0x118 -#define CXADEC_PIN_CFG1 0x11C -#define CXADEC_PIN_CFG2 0x120 - -#define CXADEC_PIN_CFG3 0x124 -#define CXADEC_I2S_MCLK 0x127 - -#define CXADEC_AUD_LOCK1 0x128 -#define CXADEC_AUD_LOCK2 0x12C -#define CXADEC_POWER_CTRL 0x130 -#define CXADEC_AFE_DIAG_CTRL1 0x134 -#define CXADEC_AFE_DIAG_CTRL2 0x138 -#define CXADEC_AFE_DIAG_CTRL3 0x13C -#define CXADEC_PLL_DIAG_CTRL 0x140 -#define CXADEC_TEST_CTRL1 0x144 -#define CXADEC_TEST_CTRL2 0x148 -#define CXADEC_BIST_STAT 0x14C -#define CXADEC_DLL1_DIAG_CTRL 0x158 -#define CXADEC_DLL2_DIAG_CTRL 0x15C - -/* IR registers */ -#define CXADEC_IR_CTRL_REG 0x200 -#define CXADEC_IR_TXCLK_REG 0x204 -#define CXADEC_IR_RXCLK_REG 0x208 -#define CXADEC_IR_CDUTY_REG 0x20C -#define CXADEC_IR_STAT_REG 0x210 -#define CXADEC_IR_IRQEN_REG 0x214 -#define CXADEC_IR_FILTER_REG 0x218 -#define CXADEC_IR_FIFO_REG 0x21C - -/* Video Registers */ -#define CXADEC_MODE_CTRL 0x400 -#define CXADEC_OUT_CTRL1 0x404 -#define CXADEC_OUT_CTRL2 0x408 -#define CXADEC_GEN_STAT 0x40C -#define CXADEC_INT_STAT_MASK 0x410 -#define CXADEC_LUMA_CTRL 0x414 - -#define CXADEC_BRIGHTNESS_CTRL_BYTE 0x414 -#define CXADEC_CONTRAST_CTRL_BYTE 0x415 -#define CXADEC_LUMA_CTRL_BYTE_3 0x416 - -#define CXADEC_HSCALE_CTRL 0x418 -#define CXADEC_VSCALE_CTRL 0x41C - -#define CXADEC_CHROMA_CTRL 0x420 - -#define CXADEC_USAT_CTRL_BYTE 0x420 -#define CXADEC_VSAT_CTRL_BYTE 0x421 -#define CXADEC_HUE_CTRL_BYTE 0x422 - -#define CXADEC_VBI_LINE_CTRL1 0x424 -#define CXADEC_VBI_LINE_CTRL2 0x428 -#define CXADEC_VBI_LINE_CTRL3 0x42C -#define CXADEC_VBI_LINE_CTRL4 0x430 -#define CXADEC_VBI_LINE_CTRL5 0x434 -#define CXADEC_VBI_FC_CFG 0x438 -#define CXADEC_VBI_MISC_CFG1 0x43C -#define CXADEC_VBI_MISC_CFG2 0x440 -#define CXADEC_VBI_PAY1 0x444 -#define CXADEC_VBI_PAY2 0x448 -#define CXADEC_VBI_CUST1_CFG1 0x44C -#define CXADEC_VBI_CUST1_CFG2 0x450 -#define CXADEC_VBI_CUST1_CFG3 0x454 -#define CXADEC_VBI_CUST2_CFG1 0x458 -#define CXADEC_VBI_CUST2_CFG2 0x45C -#define CXADEC_VBI_CUST2_CFG3 0x460 -#define CXADEC_VBI_CUST3_CFG1 0x464 -#define CXADEC_VBI_CUST3_CFG2 0x468 -#define CXADEC_VBI_CUST3_CFG3 0x46C -#define CXADEC_HORIZ_TIM_CTRL 0x470 -#define CXADEC_VERT_TIM_CTRL 0x474 -#define CXADEC_SRC_COMB_CFG 0x478 -#define CXADEC_CHROMA_VBIOFF_CFG 0x47C -#define CXADEC_FIELD_COUNT 0x480 -#define CXADEC_MISC_TIM_CTRL 0x484 -#define CXADEC_DFE_CTRL1 0x488 -#define CXADEC_DFE_CTRL2 0x48C -#define CXADEC_DFE_CTRL3 0x490 -#define CXADEC_PLL_CTRL2 0x494 -#define CXADEC_HTL_CTRL 0x498 -#define CXADEC_COMB_CTRL 0x49C -#define CXADEC_CRUSH_CTRL 0x4A0 -#define CXADEC_SOFT_RST_CTRL 0x4A4 -#define CXADEC_MV_DT_CTRL2 0x4A8 -#define CXADEC_MV_DT_CTRL3 0x4AC -#define CXADEC_MISC_DIAG_CTRL 0x4B8 - -#define CXADEC_DL_CTL 0x800 -#define CXADEC_DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */ -#define CXADEC_DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */ -#define CXADEC_DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */ -#define CXADEC_DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */ - -#define CXADEC_STD_DET_STATUS 0x804 - -#define CXADEC_STD_DET_CTL 0x808 -#define CXADEC_STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */ -#define CXADEC_STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */ - -#define CXADEC_DW8051_INT 0x80C -#define CXADEC_GENERAL_CTL 0x810 -#define CXADEC_AAGC_CTL 0x814 -#define CXADEC_IF_SRC_CTL 0x818 -#define CXADEC_ANLOG_DEMOD_CTL 0x81C -#define CXADEC_ROT_FREQ_CTL 0x820 -#define CXADEC_FM1_CTL 0x824 -#define CXADEC_PDF_CTL 0x828 -#define CXADEC_DFT1_CTL1 0x82C -#define CXADEC_DFT1_CTL2 0x830 -#define CXADEC_DFT_STATUS 0x834 -#define CXADEC_DFT2_CTL1 0x838 -#define CXADEC_DFT2_CTL2 0x83C -#define CXADEC_DFT2_STATUS 0x840 -#define CXADEC_DFT3_CTL1 0x844 -#define CXADEC_DFT3_CTL2 0x848 -#define CXADEC_DFT3_STATUS 0x84C -#define CXADEC_DFT4_CTL1 0x850 -#define CXADEC_DFT4_CTL2 0x854 -#define CXADEC_DFT4_STATUS 0x858 -#define CXADEC_AM_MTS_DET 0x85C -#define CXADEC_ANALOG_MUX_CTL 0x860 -#define CXADEC_DIG_PLL_CTL1 0x864 -#define CXADEC_DIG_PLL_CTL2 0x868 -#define CXADEC_DIG_PLL_CTL3 0x86C -#define CXADEC_DIG_PLL_CTL4 0x870 -#define CXADEC_DIG_PLL_CTL5 0x874 -#define CXADEC_DEEMPH_GAIN_CTL 0x878 -#define CXADEC_DEEMPH_COEF1 0x87C -#define CXADEC_DEEMPH_COEF2 0x880 -#define CXADEC_DBX1_CTL1 0x884 -#define CXADEC_DBX1_CTL2 0x888 -#define CXADEC_DBX1_STATUS 0x88C -#define CXADEC_DBX2_CTL1 0x890 -#define CXADEC_DBX2_CTL2 0x894 -#define CXADEC_DBX2_STATUS 0x898 -#define CXADEC_AM_FM_DIFF 0x89C - -/* NICAM registers go here */ -#define CXADEC_NICAM_STATUS 0x8C8 -#define CXADEC_DEMATRIX_CTL 0x8CC - -#define CXADEC_PATH1_CTL1 0x8D0 -#define CXADEC_PATH1_VOL_CTL 0x8D4 -#define CXADEC_PATH1_EQ_CTL 0x8D8 -#define CXADEC_PATH1_SC_CTL 0x8DC - -#define CXADEC_PATH2_CTL1 0x8E0 -#define CXADEC_PATH2_VOL_CTL 0x8E4 -#define CXADEC_PATH2_EQ_CTL 0x8E8 -#define CXADEC_PATH2_SC_CTL 0x8EC - -#define CXADEC_SRC_CTL 0x8F0 -#define CXADEC_SRC_LF_COEF 0x8F4 -#define CXADEC_SRC1_CTL 0x8F8 -#define CXADEC_SRC2_CTL 0x8FC -#define CXADEC_SRC3_CTL 0x900 -#define CXADEC_SRC4_CTL 0x904 -#define CXADEC_SRC5_CTL 0x908 -#define CXADEC_SRC6_CTL 0x90C - -#define CXADEC_BASEBAND_OUT_SEL 0x910 -#define CXADEC_I2S_IN_CTL 0x914 -#define CXADEC_I2S_OUT_CTL 0x918 -#define CXADEC_AC97_CTL 0x91C -#define CXADEC_QAM_PDF 0x920 -#define CXADEC_QAM_CONST_DEC 0x924 -#define CXADEC_QAM_ROTATOR_FREQ 0x948 - -/* Bit definitions / settings used in Mako Audio */ -#define CXADEC_PREF_MODE_MONO_LANGA 0 -#define CXADEC_PREF_MODE_MONO_LANGB 1 -#define CXADEC_PREF_MODE_MONO_LANGC 2 -#define CXADEC_PREF_MODE_FALLBACK 3 -#define CXADEC_PREF_MODE_STEREO 4 -#define CXADEC_PREF_MODE_DUAL_LANG_AC 5 -#define CXADEC_PREF_MODE_DUAL_LANG_BC 6 -#define CXADEC_PREF_MODE_DUAL_LANG_AB 7 - - -#define CXADEC_DETECT_STEREO 1 -#define CXADEC_DETECT_DUAL 2 -#define CXADEC_DETECT_TRI 4 -#define CXADEC_DETECT_SAP 0x10 -#define CXADEC_DETECT_NO_SIGNAL 0xFF - -#define CXADEC_SELECT_AUDIO_STANDARD_BG 0xF0 /* NICAM BG and A2 BG */ -#define CXADEC_SELECT_AUDIO_STANDARD_DK1 0xF1 /* NICAM DK and A2 DK */ -#define CXADEC_SELECT_AUDIO_STANDARD_DK2 0xF2 -#define CXADEC_SELECT_AUDIO_STANDARD_DK3 0xF3 -#define CXADEC_SELECT_AUDIO_STANDARD_I 0xF4 /* NICAM I and A1 */ -#define CXADEC_SELECT_AUDIO_STANDARD_L 0xF5 /* NICAM L and System L AM */ -#define CXADEC_SELECT_AUDIO_STANDARD_BTSC 0xF6 -#define CXADEC_SELECT_AUDIO_STANDARD_EIAJ 0xF7 -#define CXADEC_SELECT_AUDIO_STANDARD_A2_M 0xF8 /* A2 M */ -#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */ -#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */ - -static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd) -{ - return container_of(sd, struct cx18_av_state, sd); -} - -static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl) -{ - return &container_of(ctrl->handler, struct cx18_av_state, hdl)->sd; -} - -/* ----------------------------------------------------------------------- */ -/* cx18_av-core.c */ -int cx18_av_write(struct cx18 *cx, u16 addr, u8 value); -int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value); -int cx18_av_write4_noretry(struct cx18 *cx, u16 addr, u32 value); -int cx18_av_write_expect(struct cx18 *cx, u16 addr, u8 value, u8 eval, u8 mask); -int cx18_av_write4_expect(struct cx18 *cx, u16 addr, u32 value, u32 eval, - u32 mask); -u8 cx18_av_read(struct cx18 *cx, u16 addr); -u32 cx18_av_read4(struct cx18 *cx, u16 addr); -int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value); -int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value); -void cx18_av_std_setup(struct cx18 *cx); - -int cx18_av_probe(struct cx18 *cx); - -/* ----------------------------------------------------------------------- */ -/* cx18_av-firmware.c */ -int cx18_av_loadfw(struct cx18 *cx); - -/* ----------------------------------------------------------------------- */ -/* cx18_av-audio.c */ -int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq); -void cx18_av_audio_set_path(struct cx18 *cx); -extern const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops; - -/* ----------------------------------------------------------------------- */ -/* cx18_av-vbi.c */ -int cx18_av_decode_vbi_line(struct v4l2_subdev *sd, - struct v4l2_decode_vbi_line *vbi); -int cx18_av_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt); -int cx18_av_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); -int cx18_av_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt); - -#endif diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c deleted file mode 100644 index a34fd082b76..00000000000 --- a/drivers/media/video/cx18/cx18-av-firmware.c +++ /dev/null @@ -1,225 +0,0 @@ -/* - * cx18 ADEC firmware functions - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include <linux/firmware.h> - -#define CX18_AUDIO_ENABLE 0xc72014 -#define CX18_AI1_MUX_MASK 0x30 -#define CX18_AI1_MUX_I2S1 0x00 -#define CX18_AI1_MUX_I2S2 0x10 -#define CX18_AI1_MUX_843_I2S 0x20 -#define CX18_AI1_MUX_INVALID 0x30 - -#define FWFILE "v4l-cx23418-dig.fw" - -static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw) -{ - struct v4l2_subdev *sd = &cx->av_state.sd; - int ret = 0; - const u8 *data; - u32 size; - int addr; - u32 expected, dl_control; - - /* Ensure we put the 8051 in reset and enable firmware upload mode */ - dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); - do { - dl_control &= 0x00ffffff; - dl_control |= 0x0f000000; - cx18_av_write4_noretry(cx, CXADEC_DL_CTL, dl_control); - dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); - } while ((dl_control & 0xff000000) != 0x0f000000); - - /* Read and auto increment until at address 0x0000 */ - while (dl_control & 0x3fff) - dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); - - data = fw->data; - size = fw->size; - for (addr = 0; addr < size; addr++) { - dl_control &= 0xffff3fff; /* ignore top 2 bits of address */ - expected = 0x0f000000 | ((u32)data[addr] << 16) | addr; - if (expected != dl_control) { - CX18_ERR_DEV(sd, "verification of %s firmware load " - "failed: expected %#010x got %#010x\n", - FWFILE, expected, dl_control); - ret = -EIO; - break; - } - dl_control = cx18_av_read4(cx, CXADEC_DL_CTL); - } - if (ret == 0) - CX18_INFO_DEV(sd, "verified load of %s firmware (%d bytes)\n", - FWFILE, size); - return ret; -} - -int cx18_av_loadfw(struct cx18 *cx) -{ - struct v4l2_subdev *sd = &cx->av_state.sd; - const struct firmware *fw = NULL; - u32 size; - u32 u, v; - const u8 *ptr; - int i; - int retries1 = 0; - - if (request_firmware(&fw, FWFILE, &cx->pci_dev->dev) != 0) { - CX18_ERR_DEV(sd, "unable to open firmware %s\n", FWFILE); - return -EINVAL; - } - - /* The firmware load often has byte errors, so allow for several - retries, both at byte level and at the firmware load level. */ - while (retries1 < 5) { - cx18_av_write4_expect(cx, CXADEC_CHIP_CTRL, 0x00010000, - 0x00008430, 0xffffffff); /* cx25843 */ - cx18_av_write_expect(cx, CXADEC_STD_DET_CTL, 0xf6, 0xf6, 0xff); - - /* Reset the Mako core, Register is alias of CXADEC_CHIP_CTRL */ - cx18_av_write4_expect(cx, 0x8100, 0x00010000, - 0x00008430, 0xffffffff); /* cx25843 */ - - /* Put the 8051 in reset and enable firmware upload */ - cx18_av_write4_noretry(cx, CXADEC_DL_CTL, 0x0F000000); - - ptr = fw->data; - size = fw->size; - - for (i = 0; i < size; i++) { - u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16); - u32 value = 0; - int retries2; - int unrec_err = 0; - - for (retries2 = 0; retries2 < CX18_MAX_MMIO_WR_RETRIES; - retries2++) { - cx18_av_write4_noretry(cx, CXADEC_DL_CTL, - dl_control); - udelay(10); - value = cx18_av_read4(cx, CXADEC_DL_CTL); - if (value == dl_control) - break; - /* Check if we can correct the byte by changing - the address. We can only write the lower - address byte of the address. */ - if ((value & 0x3F00) != (dl_control & 0x3F00)) { - unrec_err = 1; - break; - } - } - if (unrec_err || retries2 >= CX18_MAX_MMIO_WR_RETRIES) - break; - } - if (i == size) - break; - retries1++; - } - if (retries1 >= 5) { - CX18_ERR_DEV(sd, "unable to load firmware %s\n", FWFILE); - release_firmware(fw); - return -EIO; - } - - cx18_av_write4_expect(cx, CXADEC_DL_CTL, - 0x03000000 | fw->size, 0x03000000, 0x13000000); - - CX18_INFO_DEV(sd, "loaded %s firmware (%d bytes)\n", FWFILE, size); - - if (cx18_av_verifyfw(cx, fw) == 0) - cx18_av_write4_expect(cx, CXADEC_DL_CTL, - 0x13000000 | fw->size, 0x13000000, 0x13000000); - - /* Output to the 416 */ - cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000); - - /* Audio input control 1 set to Sony mode */ - /* Audio output input 2 is 0 for slave operation input */ - /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ - /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge - after WS transition for first bit of audio word. */ - cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0); - - /* Audio output control 1 is set to Sony mode */ - /* Audio output control 2 is set to 1 for master mode */ - /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */ - /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge - after WS transition for first bit of audio word. */ - /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT - are generated) */ - cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0); - - /* set alt I2s master clock to /0x16 and enable alt divider i2s - passthrough */ - cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5600B687); - - cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, 0x000000F6, 0x000000F6, - 0x3F00FFFF); - /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */ - - /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */ - /* Register 0x09CC is defined by the Merlin firmware, and doesn't - have a name in the spec. */ - cx18_av_write4(cx, 0x09CC, 1); - - v = cx18_read_reg(cx, CX18_AUDIO_ENABLE); - /* If bit 11 is 1, clear bit 10 */ - if (v & 0x800) - cx18_write_reg_expect(cx, v & 0xFFFFFBFF, CX18_AUDIO_ENABLE, - 0, 0x400); - - /* Toggle the AI1 MUX */ - v = cx18_read_reg(cx, CX18_AUDIO_ENABLE); - u = v & CX18_AI1_MUX_MASK; - v &= ~CX18_AI1_MUX_MASK; - if (u == CX18_AI1_MUX_843_I2S || u == CX18_AI1_MUX_INVALID) { - /* Switch to I2S1 */ - v |= CX18_AI1_MUX_I2S1; - cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, - v, CX18_AI1_MUX_MASK); - /* Switch back to the A/V decoder core I2S output */ - v = (v & ~CX18_AI1_MUX_MASK) | CX18_AI1_MUX_843_I2S; - } else { - /* Switch to the A/V decoder core I2S output */ - v |= CX18_AI1_MUX_843_I2S; - cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, - v, CX18_AI1_MUX_MASK); - /* Switch back to I2S1 or I2S2 */ - v = (v & ~CX18_AI1_MUX_MASK) | u; - } - cx18_write_reg_expect(cx, v | 0xb00, CX18_AUDIO_ENABLE, - v, CX18_AI1_MUX_MASK); - - /* Enable WW auto audio standard detection */ - v = cx18_av_read4(cx, CXADEC_STD_DET_CTL); - v |= 0xFF; /* Auto by default */ - v |= 0x400; /* Stereo by default */ - v |= 0x14000000; - cx18_av_write4_expect(cx, CXADEC_STD_DET_CTL, v, v, 0x3F00FFFF); - - release_firmware(fw); - return 0; -} - -MODULE_FIRMWARE(FWFILE); diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c deleted file mode 100644 index baa36fbcd4d..00000000000 --- a/drivers/media/video/cx18/cx18-av-vbi.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * cx18 ADEC VBI functions - * - * Derived from cx25840-vbi.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - */ - - -#include "cx18-driver.h" - -/* - * For sliced VBI output, we set up to use VIP-1.1, 8-bit mode, - * NN counts 1 byte Dwords, an IDID with the VBI line # in it. - * Thus, according to the VIP-2 Spec, our VBI ancillary data lines - * (should!) look like: - * 4 byte EAV code: 0xff 0x00 0x00 0xRP - * unknown number of possible idle bytes - * 3 byte Anc data preamble: 0x00 0xff 0xff - * 1 byte data identifier: ne010iii (parity bits, 010, DID bits) - * 1 byte secondary data id: nessssss (parity bits, SDID bits) - * 1 byte data word count: necccccc (parity bits, NN Dword count) - * 2 byte Internal DID: VBI-line-# 0x80 - * NN data bytes - * 1 byte checksum - * Fill bytes needed to fil out to 4*NN bytes of payload - * - * The RP codes for EAVs when in VIP-1.1 mode, not in raw mode, & - * in the vertical blanking interval are: - * 0xb0 (Task 0 VerticalBlank HorizontalBlank 0 0 0 0) - * 0xf0 (Task EvenField VerticalBlank HorizontalBlank 0 0 0 0) - * - * Since the V bit is only allowed to toggle in the EAV RP code, just - * before the first active region line and for active lines, they are: - * 0x90 (Task 0 0 HorizontalBlank 0 0 0 0) - * 0xd0 (Task EvenField 0 HorizontalBlank 0 0 0 0) - * - * The user application DID bytes we care about are: - * 0x91 (1 0 010 0 !ActiveLine AncDataPresent) - * 0x55 (0 1 010 2ndField !ActiveLine AncDataPresent) - * - */ -static const u8 sliced_vbi_did[2] = { 0x91, 0x55 }; - -struct vbi_anc_data { - /* u8 eav[4]; */ - /* u8 idle[]; Variable number of idle bytes */ - u8 preamble[3]; - u8 did; - u8 sdid; - u8 data_count; - u8 idid[2]; - u8 payload[1]; /* data_count of payload */ - /* u8 checksum; */ - /* u8 fill[]; Variable number of fill bytes */ -}; - -static int odd_parity(u8 c) -{ - c ^= (c >> 4); - c ^= (c >> 2); - c ^= (c >> 1); - - return c & 1; -} - -static int decode_vps(u8 *dst, u8 *p) -{ - static const u8 biphase_tbl[] = { - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, - 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, - 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, - 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, - 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, - 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87, - 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3, - 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85, - 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1, - 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5, - 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1, - 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, - 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, - 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86, - 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2, - 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84, - 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0, - 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4, - 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96, - 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2, - 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94, - 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0, - 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4, - 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0, - }; - - u8 c, err = 0; - int i; - - for (i = 0; i < 2 * 13; i += 2) { - err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]]; - c = (biphase_tbl[p[i + 1]] & 0xf) | - ((biphase_tbl[p[i]] & 0xf) << 4); - dst[i / 2] = c; - } - - return err & 0xf0; -} - -int cx18_av_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - struct cx18_av_state *state = &cx->av_state; - static const u16 lcr2vbi[] = { - 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ - 0, V4L2_SLICED_WSS_625, 0, /* 4 */ - V4L2_SLICED_CAPTION_525, /* 6 */ - 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ - 0, 0, 0, 0 - }; - int is_pal = !(state->std & V4L2_STD_525_60); - int i; - - memset(svbi, 0, sizeof(*svbi)); - /* we're done if raw VBI is active */ - if ((cx18_av_read(cx, 0x404) & 0x10) == 0) - return 0; - - if (is_pal) { - for (i = 7; i <= 23; i++) { - u8 v = cx18_av_read(cx, 0x424 + i - 7); - - svbi->service_lines[0][i] = lcr2vbi[v >> 4]; - svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; - svbi->service_set |= svbi->service_lines[0][i] | - svbi->service_lines[1][i]; - } - } else { - for (i = 10; i <= 21; i++) { - u8 v = cx18_av_read(cx, 0x424 + i - 10); - - svbi->service_lines[0][i] = lcr2vbi[v >> 4]; - svbi->service_lines[1][i] = lcr2vbi[v & 0xf]; - svbi->service_set |= svbi->service_lines[0][i] | - svbi->service_lines[1][i]; - } - } - return 0; -} - -int cx18_av_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - struct cx18_av_state *state = &cx->av_state; - - /* Setup standard */ - cx18_av_std_setup(cx); - - /* VBI Offset */ - cx18_av_write(cx, 0x47f, state->slicer_line_delay); - cx18_av_write(cx, 0x404, 0x2e); - return 0; -} - -int cx18_av_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - struct cx18_av_state *state = &cx->av_state; - int is_pal = !(state->std & V4L2_STD_525_60); - int i, x; - u8 lcr[24]; - - for (x = 0; x <= 23; x++) - lcr[x] = 0x00; - - /* Setup standard */ - cx18_av_std_setup(cx); - - /* Sliced VBI */ - cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */ - cx18_av_write(cx, 0x406, 0x13); - cx18_av_write(cx, 0x47f, state->slicer_line_delay); - - /* Force impossible lines to 0 */ - if (is_pal) { - for (i = 0; i <= 6; i++) - svbi->service_lines[0][i] = - svbi->service_lines[1][i] = 0; - } else { - for (i = 0; i <= 9; i++) - svbi->service_lines[0][i] = - svbi->service_lines[1][i] = 0; - - for (i = 22; i <= 23; i++) - svbi->service_lines[0][i] = - svbi->service_lines[1][i] = 0; - } - - /* Build register values for requested service lines */ - for (i = 7; i <= 23; i++) { - for (x = 0; x <= 1; x++) { - switch (svbi->service_lines[1-x][i]) { - case V4L2_SLICED_TELETEXT_B: - lcr[i] |= 1 << (4 * x); - break; - case V4L2_SLICED_WSS_625: - lcr[i] |= 4 << (4 * x); - break; - case V4L2_SLICED_CAPTION_525: - lcr[i] |= 6 << (4 * x); - break; - case V4L2_SLICED_VPS: - lcr[i] |= 9 << (4 * x); - break; - } - } - } - - if (is_pal) { - for (x = 1, i = 0x424; i <= 0x434; i++, x++) - cx18_av_write(cx, i, lcr[6 + x]); - } else { - for (x = 1, i = 0x424; i <= 0x430; i++, x++) - cx18_av_write(cx, i, lcr[9 + x]); - for (i = 0x431; i <= 0x434; i++) - cx18_av_write(cx, i, 0); - } - - cx18_av_write(cx, 0x43c, 0x16); - /* Should match vblank set in cx18_av_std_setup() */ - cx18_av_write(cx, 0x474, is_pal ? 38 : 26); - return 0; -} - -int cx18_av_decode_vbi_line(struct v4l2_subdev *sd, - struct v4l2_decode_vbi_line *vbi) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - struct cx18_av_state *state = &cx->av_state; - struct vbi_anc_data *anc = (struct vbi_anc_data *)vbi->p; - u8 *p; - int did, sdid, l, err = 0; - - /* - * Check for the ancillary data header for sliced VBI - */ - if (anc->preamble[0] || - anc->preamble[1] != 0xff || anc->preamble[2] != 0xff || - (anc->did != sliced_vbi_did[0] && - anc->did != sliced_vbi_did[1])) { - vbi->line = vbi->type = 0; - return 0; - } - - did = anc->did; - sdid = anc->sdid & 0xf; - l = anc->idid[0] & 0x3f; - l += state->slicer_line_offset; - p = anc->payload; - - /* Decode the SDID set by the slicer */ - switch (sdid) { - case 1: - sdid = V4L2_SLICED_TELETEXT_B; - break; - case 4: - sdid = V4L2_SLICED_WSS_625; - break; - case 6: - sdid = V4L2_SLICED_CAPTION_525; - err = !odd_parity(p[0]) || !odd_parity(p[1]); - break; - case 9: - sdid = V4L2_SLICED_VPS; - if (decode_vps(p, p) != 0) - err = 1; - break; - default: - sdid = 0; - err = 1; - break; - } - - vbi->type = err ? 0 : sdid; - vbi->line = err ? 0 : l; - vbi->is_second_field = err ? 0 : (did == sliced_vbi_did[1]); - vbi->p = p; - return 0; -} diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c deleted file mode 100644 index c07c849b1aa..00000000000 --- a/drivers/media/video/cx18/cx18-cards.c +++ /dev/null @@ -1,638 +0,0 @@ -/* - * cx18 functions to query card hardware - * - * Derived from ivtv-cards.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-cards.h" -#include "cx18-av-core.h" -#include "cx18-i2c.h" -#include <media/cs5345.h> - -#define V4L2_STD_PAL_SECAM (V4L2_STD_PAL|V4L2_STD_SECAM) - -/********************** card configuration *******************************/ - -/* usual i2c tuner addresses to probe */ -static struct cx18_card_tuner_i2c cx18_i2c_std = { - .radio = { I2C_CLIENT_END }, - .demod = { 0x43, I2C_CLIENT_END }, - .tv = { 0x61, 0x60, I2C_CLIENT_END }, -}; - -/* - * usual i2c tuner addresses to probe with additional demod address for - * an NXP TDA8295 at 0x42 (N.B. it can possibly be at 0x4b or 0x4c too). - */ -static struct cx18_card_tuner_i2c cx18_i2c_nxp = { - .radio = { I2C_CLIENT_END }, - .demod = { 0x42, 0x43, I2C_CLIENT_END }, - .tv = { 0x61, 0x60, I2C_CLIENT_END }, -}; - -/* Please add new PCI IDs to: http://pci-ids.ucw.cz/ - This keeps the PCI ID database up to date. Note that the entries - must be added under vendor 0x4444 (Conexant) as subsystem IDs. - New vendor IDs should still be added to the vendor ID list. */ - -/* Hauppauge HVR-1600 cards */ - -/* Note: for Hauppauge cards the tveeprom information is used instead - of PCI IDs */ -static const struct cx18_card cx18_card_hvr1600_esmt = { - .type = CX18_CARD_HVR_1600_ESMT, - .name = "Hauppauge HVR-1600", - .comment = "Simultaneous Digital and Analog TV capture supported\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_CS5345, - .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | - CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL | - CX18_HW_Z8F0811_IR_HAUP, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, - { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 }, - { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, - { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 }, - { CX18_CARD_INPUT_LINE_IN2, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 }, - .ddr = { - /* ESMT M13S128324A-5B memory */ - .chip_config = 0x003, - .refresh = 0x30c, - .timing1 = 0x44220e82, - .timing2 = 0x08, - .tune_lane = 0, - .initial_emrs = 0, - }, - .gpio_init.initial_value = 0x3001, - .gpio_init.direction = 0x3001, - .gpio_i2c_slave_reset = { - .active_lo_mask = 0x3001, - .msecs_asserted = 10, - .msecs_recovery = 40, - .ir_reset_mask = 0x0001, - }, - .i2c = &cx18_i2c_std, -}; - -static const struct cx18_card cx18_card_hvr1600_s5h1411 = { - .type = CX18_CARD_HVR_1600_S5H1411, - .name = "Hauppauge HVR-1600", - .comment = "Simultaneous Digital and Analog TV capture supported\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_CS5345, - .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | - CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL | - CX18_HW_Z8F0811_IR_HAUP, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, - { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 }, - { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, - { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 }, - { CX18_CARD_INPUT_LINE_IN2, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 }, - .ddr = { - /* ESMT M13S128324A-5B memory */ - .chip_config = 0x003, - .refresh = 0x30c, - .timing1 = 0x44220e82, - .timing2 = 0x08, - .tune_lane = 0, - .initial_emrs = 0, - }, - .gpio_init.initial_value = 0x3801, - .gpio_init.direction = 0x3801, - .gpio_i2c_slave_reset = { - .active_lo_mask = 0x3801, - .msecs_asserted = 10, - .msecs_recovery = 40, - .ir_reset_mask = 0x0001, - }, - .i2c = &cx18_i2c_nxp, -}; - -static const struct cx18_card cx18_card_hvr1600_samsung = { - .type = CX18_CARD_HVR_1600_SAMSUNG, - .name = "Hauppauge HVR-1600 (Preproduction)", - .comment = "Simultaneous Digital and Analog TV capture supported\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_CS5345, - .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | - CX18_HW_CS5345 | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL | - CX18_HW_Z8F0811_IR_HAUP, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE7 }, - { CX18_CARD_INPUT_SVIDEO1, 1, CX18_AV_SVIDEO1 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE3 }, - { CX18_CARD_INPUT_SVIDEO2, 2, CX18_AV_SVIDEO2 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE4 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 }, - { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_2 }, - { CX18_CARD_INPUT_LINE_IN2, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_3 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL1, CS5345_IN_4 }, - .ddr = { - /* Samsung K4D263238G-VC33 memory */ - .chip_config = 0x003, - .refresh = 0x30c, - .timing1 = 0x23230b73, - .timing2 = 0x08, - .tune_lane = 0, - .initial_emrs = 2, - }, - .gpio_init.initial_value = 0x3001, - .gpio_init.direction = 0x3001, - .gpio_i2c_slave_reset = { - .active_lo_mask = 0x3001, - .msecs_asserted = 10, - .msecs_recovery = 40, - .ir_reset_mask = 0x0001, - }, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Compro VideoMate H900: note that this card is analog only! */ - -static const struct cx18_card_pci_info cx18_pci_h900[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 }, - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_h900 = { - .type = CX18_CARD_COMPRO_H900, - .name = "Compro VideoMate H900", - .comment = "Analog TV capture supported\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, - CX18_AV_AUDIO_SERIAL1, 0 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, - CX18_AV_AUDIO_SERIAL1, 0 }, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .ddr = { - /* EtronTech EM6A9160TS-5G memory */ - .chip_config = 0x50003, - .refresh = 0x753, - .timing1 = 0x24330e84, - .timing2 = 0x1f, - .tune_lane = 0, - .initial_emrs = 0, - }, - .xceive_pin = 15, - .pci_list = cx18_pci_h900, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Yuan MPC718: not working at the moment! */ - -static const struct cx18_card_pci_info cx18_pci_mpc718[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_YUAN, 0x0718 }, - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_mpc718 = { - .type = CX18_CARD_YUAN_MPC718, - .name = "Yuan MPC718 MiniPCI DVB-T/Analog", - .comment = "Experimenters needed for device to work well.\n" - "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_GPIO_MUX, - .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | - CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, - { CX18_CARD_INPUT_SVIDEO2, 2, - CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 }, - }, - .tuners = { - /* XC3028 tuner */ - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - /* FIXME - the FM radio is just a guess and driver doesn't use SIF */ - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, - .ddr = { - /* Hynix HY5DU283222B DDR RAM */ - .chip_config = 0x303, - .refresh = 0x3bd, - .timing1 = 0x36320966, - .timing2 = 0x1f, - .tune_lane = 0, - .initial_emrs = 2, - }, - .gpio_init.initial_value = 0x1, - .gpio_init.direction = 0x3, - /* FIXME - these GPIO's are just guesses */ - .gpio_audio_input = { .mask = 0x3, - .tuner = 0x1, - .linein = 0x3, - .radio = 0x1 }, - .xceive_pin = 0, - .pci_list = cx18_pci_mpc718, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* GoTView PCI */ - -static const struct cx18_card_pci_info cx18_pci_gotview_dvd3[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_GOTVIEW, 0x3343 }, - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_gotview_dvd3 = { - .type = CX18_CARD_GOTVIEW_PCI_DVD3, - .name = "GoTView PCI DVD3 Hybrid", - .comment = "Experimenters needed for device to work well.\n" - "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_GPIO_MUX, - .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER | - CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, - { CX18_CARD_INPUT_SVIDEO2, 2, - CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 }, - }, - .tuners = { - /* XC3028 tuner */ - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - /* FIXME - the FM radio is just a guess and driver doesn't use SIF */ - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, - .ddr = { - /* Hynix HY5DU283222B DDR RAM */ - .chip_config = 0x303, - .refresh = 0x3bd, - .timing1 = 0x36320966, - .timing2 = 0x1f, - .tune_lane = 0, - .initial_emrs = 2, - }, - .gpio_init.initial_value = 0x1, - .gpio_init.direction = 0x3, - - .gpio_audio_input = { .mask = 0x3, - .tuner = 0x1, - .linein = 0x2, - .radio = 0x1 }, - .xceive_pin = 0, - .pci_list = cx18_pci_gotview_dvd3, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Conexant Raptor PAL/SECAM: note that this card is analog only! */ - -static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_CONEXANT, 0x0009 }, - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_cnxt_raptor_pal = { - .type = CX18_CARD_CNXT_RAPTOR_PAL, - .name = "Conexant Raptor PAL/SECAM", - .comment = "Analog TV capture supported\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_GPIO_MUX, - .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, - { CX18_CARD_INPUT_SVIDEO2, 2, - CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 }, - { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 }, - }, - .tuners = { - { .std = V4L2_STD_PAL_SECAM, .tuner = TUNER_PHILIPS_FM1216ME_MK3 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO_SERIAL1, 2 }, - .ddr = { - /* MT 46V16M16 memory */ - .chip_config = 0x50306, - .refresh = 0x753, - .timing1 = 0x33220953, - .timing2 = 0x09, - .tune_lane = 0, - .initial_emrs = 0, - }, - .gpio_init.initial_value = 0x1002, - .gpio_init.direction = 0xf002, - .gpio_audio_input = { .mask = 0xf002, - .tuner = 0x1002, /* LED D1 Tuner AF */ - .linein = 0x2000, /* LED D2 Line In 1 */ - .radio = 0x4002 }, /* LED D3 Tuner AF */ - .pci_list = cx18_pci_cnxt_raptor_pal, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Toshiba Qosmio laptop internal DVB-T/Analog Hybrid Tuner */ - -static const struct cx18_card_pci_info cx18_pci_toshiba_qosmio_dvbt[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_TOSHIBA, 0x0110 }, - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_toshiba_qosmio_dvbt = { - .type = CX18_CARD_TOSHIBA_QOSMIO_DVBT, - .name = "Toshiba Qosmio DVB-T/Analog", - .comment = "Experimenters and photos needed for device to work well.\n" - "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE6 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - }, - .tuners = { - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .ddr = { - .chip_config = 0x202, - .refresh = 0x3bb, - .timing1 = 0x33320a63, - .timing2 = 0x0a, - .tune_lane = 0, - .initial_emrs = 0x42, - }, - .xceive_pin = 15, - .pci_list = cx18_pci_toshiba_qosmio_dvbt, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Leadtek WinFast PVR2100 */ - -static const struct cx18_card_pci_info cx18_pci_leadtek_pvr2100[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6f27 }, /* PVR2100 */ - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_leadtek_pvr2100 = { - .type = CX18_CARD_LEADTEK_PVR2100, - .name = "Leadtek WinFast PVR2100", - .comment = "Experimenters and photos needed for device to work well.\n" - "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_GPIO_MUX, - .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX | - CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 }, - { CX18_CARD_INPUT_COMPONENT1, 1, CX18_AV_COMPONENT1 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - }, - .tuners = { - /* XC2028 tuner */ - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, - .ddr = { - /* Pointer to proper DDR config values provided by Terry Wu */ - .chip_config = 0x303, - .refresh = 0x3bb, - .timing1 = 0x24220e83, - .timing2 = 0x1f, - .tune_lane = 0, - .initial_emrs = 0x2, - }, - .gpio_init.initial_value = 0x6, - .gpio_init.direction = 0x7, - .gpio_audio_input = { .mask = 0x7, - .tuner = 0x6, .linein = 0x2, .radio = 0x2 }, - .xceive_pin = 1, - .pci_list = cx18_pci_leadtek_pvr2100, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -/* Leadtek WinFast DVR3100 H */ - -static const struct cx18_card_pci_info cx18_pci_leadtek_dvr3100h[] = { - { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_LEADTEK, 0x6690 }, /* DVR3100 H */ - { 0, 0, 0 } -}; - -static const struct cx18_card cx18_card_leadtek_dvr3100h = { - .type = CX18_CARD_LEADTEK_DVR3100H, - .name = "Leadtek WinFast DVR3100 H", - .comment = "Simultaneous DVB-T and Analog capture supported,\n" - "\texcept when capturing Analog from the antenna input.\n", - .v4l2_capabilities = CX18_CAP_ENCODER, - .hw_audio_ctrl = CX18_HW_418_AV, - .hw_muxer = CX18_HW_GPIO_MUX, - .hw_all = CX18_HW_418_AV | CX18_HW_TUNER | CX18_HW_GPIO_MUX | - CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL, - .video_inputs = { - { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 }, - { CX18_CARD_INPUT_SVIDEO1, 1, - CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 }, - { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE7 }, - { CX18_CARD_INPUT_COMPONENT1, 1, CX18_AV_COMPONENT1 }, - }, - .audio_inputs = { - { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 }, - { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 }, - }, - .tuners = { - /* XC3028 tuner */ - { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 }, - }, - .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 }, - .ddr = { - /* Pointer to proper DDR config values provided by Terry Wu */ - .chip_config = 0x303, - .refresh = 0x3bb, - .timing1 = 0x24220e83, - .timing2 = 0x1f, - .tune_lane = 0, - .initial_emrs = 0x2, - }, - .gpio_init.initial_value = 0x6, - .gpio_init.direction = 0x7, - .gpio_audio_input = { .mask = 0x7, - .tuner = 0x6, .linein = 0x2, .radio = 0x2 }, - .xceive_pin = 1, - .pci_list = cx18_pci_leadtek_dvr3100h, - .i2c = &cx18_i2c_std, -}; - -/* ------------------------------------------------------------------------- */ - -static const struct cx18_card *cx18_card_list[] = { - &cx18_card_hvr1600_esmt, - &cx18_card_hvr1600_samsung, - &cx18_card_h900, - &cx18_card_mpc718, - &cx18_card_cnxt_raptor_pal, - &cx18_card_toshiba_qosmio_dvbt, - &cx18_card_leadtek_pvr2100, - &cx18_card_leadtek_dvr3100h, - &cx18_card_gotview_dvd3, - &cx18_card_hvr1600_s5h1411 -}; - -const struct cx18_card *cx18_get_card(u16 index) -{ - if (index >= ARRAY_SIZE(cx18_card_list)) - return NULL; - return cx18_card_list[index]; -} - -int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input) -{ - const struct cx18_card_video_input *card_input = - cx->card->video_inputs + index; - static const char * const input_strs[] = { - "Tuner 1", - "S-Video 1", - "S-Video 2", - "Composite 1", - "Composite 2", - "Component 1" - }; - - if (index >= cx->nof_inputs) - return -EINVAL; - input->index = index; - strlcpy(input->name, input_strs[card_input->video_type - 1], - sizeof(input->name)); - input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ? - V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA); - input->audioset = (1 << cx->nof_audio_inputs) - 1; - input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ? - cx->tuner_std : V4L2_STD_ALL; - return 0; -} - -int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio) -{ - const struct cx18_card_audio_input *aud_input = - cx->card->audio_inputs + index; - static const char * const input_strs[] = { - "Tuner 1", - "Line In 1", - "Line In 2" - }; - - memset(audio, 0, sizeof(*audio)); - if (index >= cx->nof_audio_inputs) - return -EINVAL; - strlcpy(audio->name, input_strs[aud_input->audio_type - 1], - sizeof(audio->name)); - audio->index = index; - audio->capability = V4L2_AUDCAP_STEREO; - return 0; -} diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h deleted file mode 100644 index add7391ecab..00000000000 --- a/drivers/media/video/cx18/cx18-cards.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * cx18 functions to query card hardware - * - * Derived from ivtv-cards.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* hardware flags */ -#define CX18_HW_TUNER (1 << 0) -#define CX18_HW_TVEEPROM (1 << 1) -#define CX18_HW_CS5345 (1 << 2) -#define CX18_HW_DVB (1 << 3) -#define CX18_HW_418_AV (1 << 4) -#define CX18_HW_GPIO_MUX (1 << 5) -#define CX18_HW_GPIO_RESET_CTRL (1 << 6) -#define CX18_HW_Z8F0811_IR_TX_HAUP (1 << 7) -#define CX18_HW_Z8F0811_IR_RX_HAUP (1 << 8) -#define CX18_HW_Z8F0811_IR_HAUP (CX18_HW_Z8F0811_IR_RX_HAUP | \ - CX18_HW_Z8F0811_IR_TX_HAUP) - -#define CX18_HW_IR_ANY (CX18_HW_Z8F0811_IR_RX_HAUP | \ - CX18_HW_Z8F0811_IR_TX_HAUP) - -/* video inputs */ -#define CX18_CARD_INPUT_VID_TUNER 1 -#define CX18_CARD_INPUT_SVIDEO1 2 -#define CX18_CARD_INPUT_SVIDEO2 3 -#define CX18_CARD_INPUT_COMPOSITE1 4 -#define CX18_CARD_INPUT_COMPOSITE2 5 -#define CX18_CARD_INPUT_COMPONENT1 6 - -/* audio inputs */ -#define CX18_CARD_INPUT_AUD_TUNER 1 -#define CX18_CARD_INPUT_LINE_IN1 2 -#define CX18_CARD_INPUT_LINE_IN2 3 - -#define CX18_CARD_MAX_VIDEO_INPUTS 6 -#define CX18_CARD_MAX_AUDIO_INPUTS 3 -#define CX18_CARD_MAX_TUNERS 2 - -/* V4L2 capability aliases */ -#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \ - V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \ - V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) - -struct cx18_card_video_input { - u8 video_type; /* video input type */ - u8 audio_index; /* index in cx18_card_audio_input array */ - u32 video_input; /* hardware video input */ -}; - -struct cx18_card_audio_input { - u8 audio_type; /* audio input type */ - u32 audio_input; /* hardware audio input */ - u16 muxer_input; /* hardware muxer input for boards with a - multiplexer chip */ -}; - -struct cx18_card_pci_info { - u16 device; - u16 subsystem_vendor; - u16 subsystem_device; -}; - -/* GPIO definitions */ - -/* The mask is the set of bits used by the operation */ - -struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */ - u32 direction; /* DIR setting. Leave to 0 if no init is needed */ - u32 initial_value; -}; - -struct cx18_gpio_i2c_slave_reset { - u32 active_lo_mask; /* GPIO outputs that reset i2c chips when low */ - u32 active_hi_mask; /* GPIO outputs that reset i2c chips when high */ - int msecs_asserted; /* time period reset must remain asserted */ - int msecs_recovery; /* time after deassert for chips to be ready */ - u32 ir_reset_mask; /* GPIO to reset the Zilog Z8F0811 IR contoller */ -}; - -struct cx18_gpio_audio_input { /* select tuner/line in input */ - u32 mask; /* leave to 0 if not supported */ - u32 tuner; - u32 linein; - u32 radio; -}; - -struct cx18_card_tuner { - v4l2_std_id std; /* standard for which the tuner is suitable */ - int tuner; /* tuner ID (from tuner.h) */ -}; - -struct cx18_card_tuner_i2c { - unsigned short radio[2];/* radio tuner i2c address to probe */ - unsigned short demod[3];/* demodulator i2c address to probe */ - unsigned short tv[4]; /* tv tuner i2c addresses to probe */ -}; - -struct cx18_ddr { /* DDR config data */ - u32 chip_config; - u32 refresh; - u32 timing1; - u32 timing2; - u32 tune_lane; - u32 initial_emrs; -}; - -/* for card information/parameters */ -struct cx18_card { - int type; - char *name; - char *comment; - u32 v4l2_capabilities; - u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only - 1 dev allowed currently) */ - u32 hw_muxer; /* hardware used to multiplex audio input */ - u32 hw_all; /* all hardware used by the board */ - struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS]; - struct cx18_card_audio_input audio_inputs[CX18_CARD_MAX_AUDIO_INPUTS]; - struct cx18_card_audio_input radio_input; - - /* GPIO card-specific settings */ - u8 xceive_pin; /* XCeive tuner GPIO reset pin */ - struct cx18_gpio_init gpio_init; - struct cx18_gpio_i2c_slave_reset gpio_i2c_slave_reset; - struct cx18_gpio_audio_input gpio_audio_input; - - struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS]; - struct cx18_card_tuner_i2c *i2c; - - struct cx18_ddr ddr; - - /* list of device and subsystem vendor/devices that - correspond to this card type. */ - const struct cx18_card_pci_info *pci_list; -}; - -int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input); -int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *input); -const struct cx18_card *cx18_get_card(u16 index); diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c deleted file mode 100644 index 282a3d29fda..00000000000 --- a/drivers/media/video/cx18/cx18-controls.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * cx18 ioctl control functions - * - * Derived from ivtv-controls.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ -#include <linux/kernel.h> -#include <linux/slab.h> - -#include "cx18-driver.h" -#include "cx18-cards.h" -#include "cx18-ioctl.h" -#include "cx18-audio.h" -#include "cx18-mailbox.h" -#include "cx18-controls.h" - -static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) -{ - struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); - int type = cxhdl->stream_type->val; - - if (atomic_read(&cx->ana_capturing) > 0) - return -EBUSY; - - if (fmt != V4L2_MPEG_STREAM_VBI_FMT_IVTV || - !(type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS || - type == V4L2_MPEG_STREAM_TYPE_MPEG2_DVD || - type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) { - /* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */ - cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE; - CX18_DEBUG_INFO("disabled insertion of sliced VBI data into " - "the MPEG stream\n"); - return 0; - } - - /* Allocate sliced VBI buffers if needed. */ - if (cx->vbi.sliced_mpeg_data[0] == NULL) { - int i; - - for (i = 0; i < CX18_VBI_FRAMES; i++) { - cx->vbi.sliced_mpeg_data[i] = - kmalloc(CX18_SLICED_MPEG_DATA_BUFSZ, GFP_KERNEL); - if (cx->vbi.sliced_mpeg_data[i] == NULL) { - while (--i >= 0) { - kfree(cx->vbi.sliced_mpeg_data[i]); - cx->vbi.sliced_mpeg_data[i] = NULL; - } - cx->vbi.insert_mpeg = - V4L2_MPEG_STREAM_VBI_FMT_NONE; - CX18_WARN("Unable to allocate buffers for " - "sliced VBI data insertion\n"); - return -ENOMEM; - } - } - } - - cx->vbi.insert_mpeg = fmt; - CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS," - "when sliced VBI is enabled\n"); - - /* - * If our current settings have no lines set for capture, store a valid, - * default set of service lines to capture, in our current settings. - */ - if (cx18_get_service_set(cx->vbi.sliced_in) == 0) { - if (cx->is_60hz) - cx->vbi.sliced_in->service_set = - V4L2_SLICED_CAPTION_525; - else - cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625; - cx18_expand_service_set(cx->vbi.sliced_in, cx->is_50hz); - } - return 0; -} - -static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val) -{ - struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); - int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1; - struct v4l2_mbus_framefmt fmt; - - /* fix videodecoder resolution */ - fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1); - fmt.height = cxhdl->height; - fmt.code = V4L2_MBUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt); - return 0; -} - -static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx) -{ - static const u32 freqs[3] = { 44100, 48000, 32000 }; - struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); - - /* The audio clock of the digitizer must match the codec sample - rate otherwise you get some very strange effects. */ - if (idx < ARRAY_SIZE(freqs)) - cx18_call_all(cx, audio, s_clock_freq, freqs[idx]); - return 0; -} - -static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val) -{ - struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl); - - cx->dualwatch_stereo_mode = val; - return 0; -} - -struct cx2341x_handler_ops cx18_cxhdl_ops = { - .s_audio_mode = cx18_s_audio_mode, - .s_audio_sampling_freq = cx18_s_audio_sampling_freq, - .s_video_encoding = cx18_s_video_encoding, - .s_stream_vbi_fmt = cx18_s_stream_vbi_fmt, -}; diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h deleted file mode 100644 index cb5dfc7b205..00000000000 --- a/drivers/media/video/cx18/cx18-controls.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * cx18 ioctl control functions - * - * Derived from ivtv-controls.h - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -extern struct cx2341x_handler_ops cx18_cxhdl_ops; diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c deleted file mode 100644 index c67733d32c8..00000000000 --- a/drivers/media/video/cx18/cx18-driver.c +++ /dev/null @@ -1,1360 +0,0 @@ -/* - * cx18 driver initialization and card probing - * - * Derived from ivtv-driver.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-version.h" -#include "cx18-cards.h" -#include "cx18-i2c.h" -#include "cx18-irq.h" -#include "cx18-gpio.h" -#include "cx18-firmware.h" -#include "cx18-queue.h" -#include "cx18-streams.h" -#include "cx18-av-core.h" -#include "cx18-scb.h" -#include "cx18-mailbox.h" -#include "cx18-ioctl.h" -#include "cx18-controls.h" -#include "tuner-xc2028.h" -#include <linux/dma-mapping.h> -#include <media/tveeprom.h> - -/* If you have already X v4l cards, then set this to X. This way - the device numbers stay matched. Example: you have a WinTV card - without radio and a Compro H900 with. Normally this would give a - video1 device together with a radio0 device for the Compro. By - setting this to 1 you ensure that radio0 is now also radio1. */ -int cx18_first_minor; - -/* Callback for registering extensions */ -int (*cx18_ext_init)(struct cx18 *); -EXPORT_SYMBOL(cx18_ext_init); - -/* add your revision and whatnot here */ -static struct pci_device_id cx18_pci_tbl[] __devinitdata = { - {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418, - PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - {0,} -}; - -MODULE_DEVICE_TABLE(pci, cx18_pci_tbl); - -static atomic_t cx18_instance = ATOMIC_INIT(0); - -/* Parameter declarations */ -static int cardtype[CX18_MAX_CARDS]; -static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1 }; -static unsigned cardtype_c = 1; -static unsigned tuner_c = 1; -static unsigned radio_c = 1; -static char pal[] = "--"; -static char secam[] = "--"; -static char ntsc[] = "-"; - -/* Buffers */ -static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS; -static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS; -static int enc_idx_buffers = CX18_DEFAULT_ENC_IDX_BUFFERS; -static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS; -static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS; -static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS; - -static int enc_ts_bufsize = CX18_DEFAULT_ENC_TS_BUFSIZE; -static int enc_mpg_bufsize = CX18_DEFAULT_ENC_MPG_BUFSIZE; -static int enc_idx_bufsize = CX18_DEFAULT_ENC_IDX_BUFSIZE; -static int enc_yuv_bufsize = CX18_DEFAULT_ENC_YUV_BUFSIZE; -static int enc_pcm_bufsize = CX18_DEFAULT_ENC_PCM_BUFSIZE; - -static int enc_ts_bufs = -1; -static int enc_mpg_bufs = -1; -static int enc_idx_bufs = CX18_MAX_FW_MDLS_PER_STREAM; -static int enc_yuv_bufs = -1; -static int enc_vbi_bufs = -1; -static int enc_pcm_bufs = -1; - - -static int cx18_pci_latency = 1; - -static int mmio_ndelay; -static int retry_mmio = 1; - -int cx18_debug; - -module_param_array(tuner, int, &tuner_c, 0644); -module_param_array(radio, int, &radio_c, 0644); -module_param_array(cardtype, int, &cardtype_c, 0644); -module_param_string(pal, pal, sizeof(pal), 0644); -module_param_string(secam, secam, sizeof(secam), 0644); -module_param_string(ntsc, ntsc, sizeof(ntsc), 0644); -module_param_named(debug, cx18_debug, int, 0644); -module_param(mmio_ndelay, int, 0644); -module_param(retry_mmio, int, 0644); -module_param(cx18_pci_latency, int, 0644); -module_param(cx18_first_minor, int, 0644); - -module_param(enc_ts_buffers, int, 0644); -module_param(enc_mpg_buffers, int, 0644); -module_param(enc_idx_buffers, int, 0644); -module_param(enc_yuv_buffers, int, 0644); -module_param(enc_vbi_buffers, int, 0644); -module_param(enc_pcm_buffers, int, 0644); - -module_param(enc_ts_bufsize, int, 0644); -module_param(enc_mpg_bufsize, int, 0644); -module_param(enc_idx_bufsize, int, 0644); -module_param(enc_yuv_bufsize, int, 0644); -module_param(enc_pcm_bufsize, int, 0644); - -module_param(enc_ts_bufs, int, 0644); -module_param(enc_mpg_bufs, int, 0644); -module_param(enc_idx_bufs, int, 0644); -module_param(enc_yuv_bufs, int, 0644); -module_param(enc_vbi_bufs, int, 0644); -module_param(enc_pcm_bufs, int, 0644); - -MODULE_PARM_DESC(tuner, "Tuner type selection,\n" - "\t\t\tsee tuner.h for values"); -MODULE_PARM_DESC(radio, - "Enable or disable the radio. Use only if autodetection\n" - "\t\t\tfails. 0 = disable, 1 = enable"); -MODULE_PARM_DESC(cardtype, - "Only use this option if your card is not detected properly.\n" - "\t\tSpecify card type:\n" - "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n" - "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n" - "\t\t\t 3 = Compro VideoMate H900\n" - "\t\t\t 4 = Yuan MPC718\n" - "\t\t\t 5 = Conexant Raptor PAL/SECAM\n" - "\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n" - "\t\t\t 7 = Leadtek WinFast PVR2100\n" - "\t\t\t 8 = Leadtek WinFast DVR3100 H\n" - "\t\t\t 9 = GoTView PCI DVD3 Hybrid\n" - "\t\t\t 10 = Hauppauge HVR 1600 (S5H1411)\n" - "\t\t\t 0 = Autodetect (default)\n" - "\t\t\t-1 = Ignore this card\n\t\t"); -MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60"); -MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC"); -MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K"); -MODULE_PARM_DESC(debug, - "Debug level (bitmask). Default: 0\n" - "\t\t\t 1/0x0001: warning\n" - "\t\t\t 2/0x0002: info\n" - "\t\t\t 4/0x0004: mailbox\n" - "\t\t\t 8/0x0008: dma\n" - "\t\t\t 16/0x0010: ioctl\n" - "\t\t\t 32/0x0020: file\n" - "\t\t\t 64/0x0040: i2c\n" - "\t\t\t128/0x0080: irq\n" - "\t\t\t256/0x0100: high volume\n"); -MODULE_PARM_DESC(cx18_pci_latency, - "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n" - "\t\t\tDefault: Yes"); -MODULE_PARM_DESC(retry_mmio, - "(Deprecated) MMIO writes are now always checked and retried\n" - "\t\t\tEffectively: 1 [Yes]"); -MODULE_PARM_DESC(mmio_ndelay, - "(Deprecated) MMIO accesses are now never purposely delayed\n" - "\t\t\tEffectively: 0 ns"); -MODULE_PARM_DESC(enc_ts_buffers, - "Encoder TS buffer memory (MB). (enc_ts_bufs can override)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS)); -MODULE_PARM_DESC(enc_ts_bufsize, - "Size of an encoder TS buffer (kB)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFSIZE)); -MODULE_PARM_DESC(enc_ts_bufs, - "Number of encoder TS buffers\n" - "\t\t\tDefault is computed from other enc_ts_* parameters"); -MODULE_PARM_DESC(enc_mpg_buffers, - "Encoder MPG buffer memory (MB). (enc_mpg_bufs can override)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS)); -MODULE_PARM_DESC(enc_mpg_bufsize, - "Size of an encoder MPG buffer (kB)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFSIZE)); -MODULE_PARM_DESC(enc_mpg_bufs, - "Number of encoder MPG buffers\n" - "\t\t\tDefault is computed from other enc_mpg_* parameters"); -MODULE_PARM_DESC(enc_idx_buffers, - "(Deprecated) Encoder IDX buffer memory (MB)\n" - "\t\t\tIgnored, except 0 disables IDX buffer allocations\n" - "\t\t\tDefault: 1 [Enabled]"); -MODULE_PARM_DESC(enc_idx_bufsize, - "Size of an encoder IDX buffer (kB)\n" - "\t\t\tAllowed values are multiples of 1.5 kB rounded up\n" - "\t\t\t(multiples of size required for 64 index entries)\n" - "\t\t\tDefault: 2"); -MODULE_PARM_DESC(enc_idx_bufs, - "Number of encoder IDX buffers\n" - "\t\t\tDefault: " __stringify(CX18_MAX_FW_MDLS_PER_STREAM)); -MODULE_PARM_DESC(enc_yuv_buffers, - "Encoder YUV buffer memory (MB). (enc_yuv_bufs can override)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS)); -MODULE_PARM_DESC(enc_yuv_bufsize, - "Size of an encoder YUV buffer (kB)\n" - "\t\t\tAllowed values are multiples of 33.75 kB rounded up\n" - "\t\t\t(multiples of size required for 32 screen lines)\n" - "\t\t\tDefault: 102"); -MODULE_PARM_DESC(enc_yuv_bufs, - "Number of encoder YUV buffers\n" - "\t\t\tDefault is computed from other enc_yuv_* parameters"); -MODULE_PARM_DESC(enc_vbi_buffers, - "Encoder VBI buffer memory (MB). (enc_vbi_bufs can override)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS)); -MODULE_PARM_DESC(enc_vbi_bufs, - "Number of encoder VBI buffers\n" - "\t\t\tDefault is computed from enc_vbi_buffers"); -MODULE_PARM_DESC(enc_pcm_buffers, - "Encoder PCM buffer memory (MB). (enc_pcm_bufs can override)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS)); -MODULE_PARM_DESC(enc_pcm_bufsize, - "Size of an encoder PCM buffer (kB)\n" - "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFSIZE)); -MODULE_PARM_DESC(enc_pcm_bufs, - "Number of encoder PCM buffers\n" - "\t\t\tDefault is computed from other enc_pcm_* parameters"); - -MODULE_PARM_DESC(cx18_first_minor, - "Set device node number assigned to first card"); - -MODULE_AUTHOR("Hans Verkuil"); -MODULE_DESCRIPTION("CX23418 driver"); -MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder"); -MODULE_LICENSE("GPL"); - -MODULE_VERSION(CX18_VERSION); - -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - struct cx18 *dev = container_of(work, struct cx18, request_module_wk); - - /* Make sure cx18-alsa module is loaded */ - request_module("cx18-alsa"); - - /* Initialize cx18-alsa for this instance of the cx18 device */ - if (cx18_ext_init != NULL) - cx18_ext_init(dev); -} - -static void request_modules(struct cx18 *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} - -static void flush_request_modules(struct cx18 *dev) -{ - flush_work_sync(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#define flush_request_modules(dev) -#endif /* CONFIG_MODULES */ - -/* Generic utility functions */ -int cx18_msleep_timeout(unsigned int msecs, int intr) -{ - long int timeout = msecs_to_jiffies(msecs); - int sig; - - do { - set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); - timeout = schedule_timeout(timeout); - sig = intr ? signal_pending(current) : 0; - } while (!sig && timeout); - return sig; -} - -/* Release ioremapped memory */ -static void cx18_iounmap(struct cx18 *cx) -{ - if (cx == NULL) - return; - - /* Release io memory */ - if (cx->enc_mem != NULL) { - CX18_DEBUG_INFO("releasing enc_mem\n"); - iounmap(cx->enc_mem); - cx->enc_mem = NULL; - } -} - -static void cx18_eeprom_dump(struct cx18 *cx, unsigned char *eedata, int len) -{ - int i; - - CX18_INFO("eeprom dump:\n"); - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - CX18_INFO("eeprom %02x:", i); - printk(KERN_CONT " %02x", eedata[i]); - if (15 == (i % 16)) - printk(KERN_CONT "\n"); - } -} - -/* Hauppauge card? get values from tveeprom */ -void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv) -{ - struct i2c_client c; - u8 eedata[256]; - - memset(&c, 0, sizeof(c)); - strlcpy(c.name, "cx18 tveeprom tmp", sizeof(c.name)); - c.adapter = &cx->i2c_adap[0]; - c.addr = 0xA0 >> 1; - - memset(tv, 0, sizeof(*tv)); - if (tveeprom_read(&c, eedata, sizeof(eedata))) - return; - - switch (cx->card->type) { - case CX18_CARD_HVR_1600_ESMT: - case CX18_CARD_HVR_1600_SAMSUNG: - case CX18_CARD_HVR_1600_S5H1411: - tveeprom_hauppauge_analog(&c, tv, eedata); - break; - case CX18_CARD_YUAN_MPC718: - case CX18_CARD_GOTVIEW_PCI_DVD3: - tv->model = 0x718; - cx18_eeprom_dump(cx, eedata, sizeof(eedata)); - CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n", - eedata[2], eedata[1], eedata[4], eedata[3]); - break; - default: - tv->model = 0xffffffff; - cx18_eeprom_dump(cx, eedata, sizeof(eedata)); - break; - } -} - -static void cx18_process_eeprom(struct cx18 *cx) -{ - struct tveeprom tv; - - cx18_read_eeprom(cx, &tv); - - /* Many thanks to Steven Toth from Hauppauge for providing the - model numbers */ - /* Note: the Samsung memory models cannot be reliably determined - from the model number. Use the cardtype module option if you - have one of these preproduction models. */ - switch (tv.model) { - case 74301: /* Retail models */ - case 74321: - case 74351: /* OEM models */ - case 74361: - /* Digital side is s5h1411/tda18271 */ - cx->card = cx18_get_card(CX18_CARD_HVR_1600_S5H1411); - break; - case 74021: /* Retail models */ - case 74031: - case 74041: - case 74141: - case 74541: /* OEM models */ - case 74551: - case 74591: - case 74651: - case 74691: - case 74751: - case 74891: - /* Digital side is s5h1409/mxl5005s */ - cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); - break; - case 0x718: - return; - case 0xffffffff: - CX18_INFO("Unknown EEPROM encoding\n"); - return; - case 0: - CX18_ERR("Invalid EEPROM\n"); - return; - default: - CX18_ERR("Unknown model %d, defaulting to original HVR-1600 " - "(cardtype=1)\n", tv.model); - cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); - break; - } - - cx->v4l2_cap = cx->card->v4l2_capabilities; - cx->card_name = cx->card->name; - cx->card_i2c = cx->card->i2c; - - CX18_INFO("Autodetected %s\n", cx->card_name); - - if (tv.tuner_type == TUNER_ABSENT) - CX18_ERR("tveeprom cannot autodetect tuner!\n"); - - if (cx->options.tuner == -1) - cx->options.tuner = tv.tuner_type; - if (cx->options.radio == -1) - cx->options.radio = (tv.has_radio != 0); - - if (cx->std != 0) - /* user specified tuner standard */ - return; - - /* autodetect tuner standard */ -#define TVEEPROM_TUNER_FORMAT_ALL (V4L2_STD_B | V4L2_STD_GH | \ - V4L2_STD_MN | \ - V4L2_STD_PAL_I | \ - V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC | \ - V4L2_STD_DK) - if ((tv.tuner_formats & TVEEPROM_TUNER_FORMAT_ALL) - == TVEEPROM_TUNER_FORMAT_ALL) { - CX18_DEBUG_INFO("Worldwide tuner detected\n"); - cx->std = V4L2_STD_ALL; - } else if (tv.tuner_formats & V4L2_STD_PAL) { - CX18_DEBUG_INFO("PAL tuner detected\n"); - cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H; - } else if (tv.tuner_formats & V4L2_STD_NTSC) { - CX18_DEBUG_INFO("NTSC tuner detected\n"); - cx->std |= V4L2_STD_NTSC_M; - } else if (tv.tuner_formats & V4L2_STD_SECAM) { - CX18_DEBUG_INFO("SECAM tuner detected\n"); - cx->std |= V4L2_STD_SECAM_L; - } else { - CX18_INFO("No tuner detected, default to NTSC-M\n"); - cx->std |= V4L2_STD_NTSC_M; - } -} - -static v4l2_std_id cx18_parse_std(struct cx18 *cx) -{ - switch (pal[0]) { - case '6': - return V4L2_STD_PAL_60; - case 'b': - case 'B': - case 'g': - case 'G': - return V4L2_STD_PAL_BG; - case 'h': - case 'H': - return V4L2_STD_PAL_H; - case 'n': - case 'N': - if (pal[1] == 'c' || pal[1] == 'C') - return V4L2_STD_PAL_Nc; - return V4L2_STD_PAL_N; - case 'i': - case 'I': - return V4L2_STD_PAL_I; - case 'd': - case 'D': - case 'k': - case 'K': - return V4L2_STD_PAL_DK; - case 'M': - case 'm': - return V4L2_STD_PAL_M; - case '-': - break; - default: - CX18_WARN("pal= argument not recognised\n"); - return 0; - } - - switch (secam[0]) { - case 'b': - case 'B': - case 'g': - case 'G': - case 'h': - case 'H': - return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; - case 'd': - case 'D': - case 'k': - case 'K': - return V4L2_STD_SECAM_DK; - case 'l': - case 'L': - if (secam[1] == 'C' || secam[1] == 'c') - return V4L2_STD_SECAM_LC; - return V4L2_STD_SECAM_L; - case '-': - break; - default: - CX18_WARN("secam= argument not recognised\n"); - return 0; - } - - switch (ntsc[0]) { - case 'm': - case 'M': - return V4L2_STD_NTSC_M; - case 'j': - case 'J': - return V4L2_STD_NTSC_M_JP; - case 'k': - case 'K': - return V4L2_STD_NTSC_M_KR; - case '-': - break; - default: - CX18_WARN("ntsc= argument not recognised\n"); - return 0; - } - - /* no match found */ - return 0; -} - -static void cx18_process_options(struct cx18 *cx) -{ - int i, j; - - cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers; - cx->options.megabytes[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control only */ - - cx->stream_buffers[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufs; - cx->stream_buffers[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control, no data */ - - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = enc_ts_bufsize; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_bufsize; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_IDX] = enc_idx_bufsize; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_bufsize; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_active_samples * 36; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_bufsize; - cx->stream_buf_size[CX18_ENC_STREAM_TYPE_RAD] = 0; /* control no data */ - - /* Ensure stream_buffers & stream_buf_size are valid */ - for (i = 0; i < CX18_MAX_STREAMS; i++) { - if (cx->stream_buffers[i] == 0 || /* User said 0 buffers */ - cx->options.megabytes[i] <= 0 || /* User said 0 MB total */ - cx->stream_buf_size[i] <= 0) { /* User said buf size 0 */ - cx->options.megabytes[i] = 0; - cx->stream_buffers[i] = 0; - cx->stream_buf_size[i] = 0; - continue; - } - /* - * YUV is a special case where the stream_buf_size needs to be - * an integral multiple of 33.75 kB (storage for 32 screens - * lines to maintain alignment in case of lost buffers). - * - * IDX is a special case where the stream_buf_size should be - * an integral multiple of 1.5 kB (storage for 64 index entries - * to maintain alignment in case of lost buffers). - * - */ - if (i == CX18_ENC_STREAM_TYPE_YUV) { - cx->stream_buf_size[i] *= 1024; - cx->stream_buf_size[i] -= - (cx->stream_buf_size[i] % CX18_UNIT_ENC_YUV_BUFSIZE); - - if (cx->stream_buf_size[i] < CX18_UNIT_ENC_YUV_BUFSIZE) - cx->stream_buf_size[i] = - CX18_UNIT_ENC_YUV_BUFSIZE; - } else if (i == CX18_ENC_STREAM_TYPE_IDX) { - cx->stream_buf_size[i] *= 1024; - cx->stream_buf_size[i] -= - (cx->stream_buf_size[i] % CX18_UNIT_ENC_IDX_BUFSIZE); - - if (cx->stream_buf_size[i] < CX18_UNIT_ENC_IDX_BUFSIZE) - cx->stream_buf_size[i] = - CX18_UNIT_ENC_IDX_BUFSIZE; - } - /* - * YUV and IDX are special cases where the stream_buf_size is - * now in bytes. - * VBI is a special case where the stream_buf_size is fixed - * and already in bytes - */ - if (i == CX18_ENC_STREAM_TYPE_VBI || - i == CX18_ENC_STREAM_TYPE_YUV || - i == CX18_ENC_STREAM_TYPE_IDX) { - if (cx->stream_buffers[i] < 0) { - cx->stream_buffers[i] = - cx->options.megabytes[i] * 1024 * 1024 - / cx->stream_buf_size[i]; - } else { - /* N.B. This might round down to 0 */ - cx->options.megabytes[i] = - cx->stream_buffers[i] - * cx->stream_buf_size[i]/(1024 * 1024); - } - } else { - /* All other streams have stream_buf_size in kB here */ - if (cx->stream_buffers[i] < 0) { - cx->stream_buffers[i] = - cx->options.megabytes[i] * 1024 - / cx->stream_buf_size[i]; - } else { - /* N.B. This might round down to 0 */ - cx->options.megabytes[i] = - cx->stream_buffers[i] - * cx->stream_buf_size[i] / 1024; - } - /* convert from kB to bytes */ - cx->stream_buf_size[i] *= 1024; - } - CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, " - "%d bytes\n", i, cx->options.megabytes[i], - cx->stream_buffers[i], cx->stream_buf_size[i]); - } - - cx->options.cardtype = cardtype[cx->instance]; - cx->options.tuner = tuner[cx->instance]; - cx->options.radio = radio[cx->instance]; - - cx->std = cx18_parse_std(cx); - if (cx->options.cardtype == -1) { - CX18_INFO("Ignore card\n"); - return; - } - cx->card = cx18_get_card(cx->options.cardtype - 1); - if (cx->card) - CX18_INFO("User specified %s card\n", cx->card->name); - else if (cx->options.cardtype != 0) - CX18_ERR("Unknown user specified type, trying to autodetect card\n"); - if (cx->card == NULL) { - if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) { - cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); - CX18_INFO("Autodetected Hauppauge card\n"); - } - } - if (cx->card == NULL) { - for (i = 0; (cx->card = cx18_get_card(i)); i++) { - if (cx->card->pci_list == NULL) - continue; - for (j = 0; cx->card->pci_list[j].device; j++) { - if (cx->pci_dev->device != - cx->card->pci_list[j].device) - continue; - if (cx->pci_dev->subsystem_vendor != - cx->card->pci_list[j].subsystem_vendor) - continue; - if (cx->pci_dev->subsystem_device != - cx->card->pci_list[j].subsystem_device) - continue; - CX18_INFO("Autodetected %s card\n", cx->card->name); - goto done; - } - } - } -done: - - if (cx->card == NULL) { - cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); - CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n", - cx->pci_dev->vendor, cx->pci_dev->device); - CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n", - cx->pci_dev->subsystem_vendor, - cx->pci_dev->subsystem_device); - CX18_ERR("Defaulting to %s card\n", cx->card->name); - CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); - CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n"); - CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n"); - } - cx->v4l2_cap = cx->card->v4l2_capabilities; - cx->card_name = cx->card->name; - cx->card_i2c = cx->card->i2c; -} - -static int __devinit cx18_create_in_workq(struct cx18 *cx) -{ - snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in", - cx->v4l2_dev.name); - cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0); - if (cx->in_work_queue == NULL) { - CX18_ERR("Unable to create incoming mailbox handler thread\n"); - return -ENOMEM; - } - return 0; -} - -static void __devinit cx18_init_in_work_orders(struct cx18 *cx) -{ - int i; - for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { - cx->in_work_order[i].cx = cx; - cx->in_work_order[i].str = cx->epu_debug_str; - INIT_WORK(&cx->in_work_order[i].work, cx18_in_work_handler); - } -} - -/* Precondition: the cx18 structure has been memset to 0. Only - the dev and instance fields have been filled in. - No assumptions on the card type may be made here (see cx18_init_struct2 - for that). - */ -static int __devinit cx18_init_struct1(struct cx18 *cx) -{ - int ret; - - cx->base_addr = pci_resource_start(cx->pci_dev, 0); - - mutex_init(&cx->serialize_lock); - mutex_init(&cx->gpio_lock); - mutex_init(&cx->epu2apu_mb_lock); - mutex_init(&cx->epu2cpu_mb_lock); - - ret = cx18_create_in_workq(cx); - if (ret) - return ret; - - cx18_init_in_work_orders(cx); - - /* start counting open_id at 1 */ - cx->open_id = 1; - - /* Initial settings */ - cx->cxhdl.port = CX2341X_PORT_MEMORY; - cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI; - cx->cxhdl.ops = &cx18_cxhdl_ops; - cx->cxhdl.func = cx18_api_func; - cx->cxhdl.priv = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; - ret = cx2341x_handler_init(&cx->cxhdl, 50); - if (ret) - return ret; - cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl; - - cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val; - cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val; - cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val | - (cx->cxhdl.video_temporal_filter_mode->cur.val << 1) | - (cx->cxhdl.video_median_filter_type->cur.val << 2); - - init_waitqueue_head(&cx->cap_w); - init_waitqueue_head(&cx->mb_apu_waitq); - init_waitqueue_head(&cx->mb_cpu_waitq); - init_waitqueue_head(&cx->dma_waitq); - - /* VBI */ - cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; - cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced; - - /* IVTV style VBI insertion into MPEG streams */ - INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_buf.list); - INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.list); - INIT_LIST_HEAD(&cx->vbi.sliced_mpeg_mdl.buf_list); - list_add(&cx->vbi.sliced_mpeg_buf.list, - &cx->vbi.sliced_mpeg_mdl.buf_list); - return 0; -} - -/* Second initialization part. Here the card type has been - autodetected. */ -static void __devinit cx18_init_struct2(struct cx18 *cx) -{ - int i; - - for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++) - if (cx->card->video_inputs[i].video_type == 0) - break; - cx->nof_inputs = i; - for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++) - if (cx->card->audio_inputs[i].audio_type == 0) - break; - cx->nof_audio_inputs = i; - - /* Find tuner input */ - for (i = 0; i < cx->nof_inputs; i++) { - if (cx->card->video_inputs[i].video_type == - CX18_CARD_INPUT_VID_TUNER) - break; - } - if (i == cx->nof_inputs) - i = 0; - cx->active_input = i; - cx->audio_input = cx->card->video_inputs[i].audio_index; -} - -static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - u16 cmd; - unsigned char pci_latency; - - CX18_DEBUG_INFO("Enabling pci device\n"); - - if (pci_enable_device(pci_dev)) { - CX18_ERR("Can't enable device %d!\n", cx->instance); - return -EIO; - } - if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32))) { - CX18_ERR("No suitable DMA available, card %d\n", cx->instance); - return -EIO; - } - if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) { - CX18_ERR("Cannot request encoder memory region, card %d\n", - cx->instance); - return -EIO; - } - - /* Enable bus mastering and memory mapped IO for the CX23418 */ - pci_read_config_word(pci_dev, PCI_COMMAND, &cmd); - cmd |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; - pci_write_config_word(pci_dev, PCI_COMMAND, cmd); - - cx->card_rev = pci_dev->revision; - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); - - if (pci_latency < 64 && cx18_pci_latency) { - CX18_INFO("Unreasonably low latency timer, " - "setting to 64 (was %d)\n", pci_latency); - pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64); - pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); - } - - CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, " - "irq: %d, latency: %d, memory: 0x%llx\n", - cx->pci_dev->device, cx->card_rev, pci_dev->bus->number, - PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn), - cx->pci_dev->irq, pci_latency, (u64)cx->base_addr); - - return 0; -} - -static void cx18_init_subdevs(struct cx18 *cx) -{ - u32 hw = cx->card->hw_all; - u32 device; - int i; - - for (i = 0, device = 1; i < 32; i++, device <<= 1) { - - if (!(device & hw)) - continue; - - switch (device) { - case CX18_HW_DVB: - case CX18_HW_TVEEPROM: - /* These subordinate devices do not use probing */ - cx->hw_flags |= device; - break; - case CX18_HW_418_AV: - /* The A/V decoder gets probed earlier to set PLLs */ - /* Just note that the card uses it (i.e. has analog) */ - cx->hw_flags |= device; - break; - case CX18_HW_GPIO_RESET_CTRL: - /* - * The Reset Controller gets probed and added to - * hw_flags earlier for i2c adapter/bus initialization - */ - break; - case CX18_HW_GPIO_MUX: - if (cx18_gpio_register(cx, device) == 0) - cx->hw_flags |= device; - break; - default: - if (cx18_i2c_register(cx, i) == 0) - cx->hw_flags |= device; - break; - } - } - - if (cx->hw_flags & CX18_HW_418_AV) - cx->sd_av = cx18_find_hw(cx, CX18_HW_418_AV); - - if (cx->card->hw_muxer != 0) - cx->sd_extmux = cx18_find_hw(cx, cx->card->hw_muxer); -} - -static int __devinit cx18_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) -{ - int retval = 0; - int i; - u32 devtype; - struct cx18 *cx; - - /* FIXME - module parameter arrays constrain max instances */ - i = atomic_inc_return(&cx18_instance) - 1; - if (i >= CX18_MAX_CARDS) { - printk(KERN_ERR "cx18: cannot manage card %d, driver has a " - "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1); - return -ENOMEM; - } - - cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC); - if (cx == NULL) { - printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n", - i); - return -ENOMEM; - } - cx->pci_dev = pci_dev; - cx->instance = i; - - retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev); - if (retval) { - printk(KERN_ERR "cx18: v4l2_device_register of card %d failed" - "\n", cx->instance); - kfree(cx); - return retval; - } - snprintf(cx->v4l2_dev.name, sizeof(cx->v4l2_dev.name), "cx18-%d", - cx->instance); - CX18_INFO("Initializing card %d\n", cx->instance); - - cx18_process_options(cx); - if (cx->options.cardtype == -1) { - retval = -ENODEV; - goto err; - } - - retval = cx18_init_struct1(cx); - if (retval) - goto err; - - CX18_DEBUG_INFO("base addr: 0x%llx\n", (u64)cx->base_addr); - - /* PCI Device Setup */ - retval = cx18_setup_pci(cx, pci_dev, pci_id); - if (retval != 0) - goto free_workqueues; - - /* map io memory */ - CX18_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n", - (u64)cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); - cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET, - CX18_MEM_SIZE); - if (!cx->enc_mem) { - CX18_ERR("ioremap failed. Can't get a window into CX23418 " - "memory and register space\n"); - CX18_ERR("Each capture card with a CX23418 needs 64 MB of " - "vmalloc address space for the window\n"); - CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); - CX18_ERR("Use the vmalloc= kernel command line option to set " - "VmallocTotal to a larger value\n"); - retval = -ENOMEM; - goto free_mem; - } - cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET; - devtype = cx18_read_reg(cx, 0xC72028); - switch (devtype & 0xff000000) { - case 0xff000000: - CX18_INFO("cx23418 revision %08x (A)\n", devtype); - break; - case 0x01000000: - CX18_INFO("cx23418 revision %08x (B)\n", devtype); - break; - default: - CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype); - break; - } - - cx18_init_power(cx, 1); - cx18_init_memory(cx); - - cx->scb = (struct cx18_scb __iomem *)(cx->enc_mem + SCB_OFFSET); - cx18_init_scb(cx); - - cx18_gpio_init(cx); - - /* Initialize integrated A/V decoder early to set PLLs, just in case */ - retval = cx18_av_probe(cx); - if (retval) { - CX18_ERR("Could not register A/V decoder subdevice\n"); - goto free_map; - } - - /* Initialize GPIO Reset Controller to do chip resets during i2c init */ - if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) { - if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0) - CX18_WARN("Could not register GPIO reset controller" - "subdevice; proceeding anyway.\n"); - else - cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL; - } - - /* active i2c */ - CX18_DEBUG_INFO("activating i2c...\n"); - retval = init_cx18_i2c(cx); - if (retval) { - CX18_ERR("Could not initialize i2c\n"); - goto free_map; - } - - if (cx->card->hw_all & CX18_HW_TVEEPROM) { - /* Based on the model number the cardtype may be changed. - The PCI IDs are not always reliable. */ - const struct cx18_card *orig_card = cx->card; - cx18_process_eeprom(cx); - - if (cx->card != orig_card) { - /* Changed the cardtype; re-reset the I2C chips */ - cx18_gpio_init(cx); - cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, - core, reset, (u32) CX18_GPIO_RESET_I2C); - } - } - if (cx->card->comment) - CX18_INFO("%s", cx->card->comment); - if (cx->card->v4l2_capabilities == 0) { - retval = -ENODEV; - goto free_i2c; - } - cx18_init_memory(cx); - cx18_init_scb(cx); - - /* Register IRQ */ - retval = request_irq(cx->pci_dev->irq, cx18_irq_handler, - IRQF_SHARED | IRQF_DISABLED, - cx->v4l2_dev.name, (void *)cx); - if (retval) { - CX18_ERR("Failed to register irq %d\n", retval); - goto free_i2c; - } - - if (cx->std == 0) - cx->std = V4L2_STD_NTSC_M; - - if (cx->options.tuner == -1) { - for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) { - if ((cx->std & cx->card->tuners[i].std) == 0) - continue; - cx->options.tuner = cx->card->tuners[i].tuner; - break; - } - } - /* if no tuner was found, then pick the first tuner in the card list */ - if (cx->options.tuner == -1 && cx->card->tuners[0].std) { - cx->std = cx->card->tuners[0].std; - if (cx->std & V4L2_STD_PAL) - cx->std = V4L2_STD_PAL_BG | V4L2_STD_PAL_H; - else if (cx->std & V4L2_STD_NTSC) - cx->std = V4L2_STD_NTSC_M; - else if (cx->std & V4L2_STD_SECAM) - cx->std = V4L2_STD_SECAM_L; - cx->options.tuner = cx->card->tuners[0].tuner; - } - if (cx->options.radio == -1) - cx->options.radio = (cx->card->radio_input.audio_type != 0); - - /* The card is now fully identified, continue with card-specific - initialization. */ - cx18_init_struct2(cx); - - cx18_init_subdevs(cx); - - if (cx->std & V4L2_STD_525_60) - cx->is_60hz = 1; - else - cx->is_50hz = 1; - - cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz); - - if (cx->options.radio > 0) - cx->v4l2_cap |= V4L2_CAP_RADIO; - - if (cx->options.tuner > -1) { - struct tuner_setup setup; - - setup.addr = ADDR_UNSET; - setup.type = cx->options.tuner; - setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */ - if (cx->options.radio > 0) - setup.mode_mask |= T_RADIO; - setup.tuner_callback = (setup.type == TUNER_XC2028) ? - cx18_reset_tuner_gpio : NULL; - cx18_call_all(cx, tuner, s_type_addr, &setup); - if (setup.type == TUNER_XC2028) { - static struct xc2028_ctrl ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - }; - struct v4l2_priv_tun_config cfg = { - .tuner = cx->options.tuner, - .priv = &ctrl, - }; - cx18_call_all(cx, tuner, s_config, &cfg); - } - } - - /* The tuner is fixed to the standard. The other inputs (e.g. S-Video) - are not. */ - cx->tuner_std = cx->std; - if (cx->std == V4L2_STD_ALL) - cx->std = V4L2_STD_NTSC_M; - - retval = cx18_streams_setup(cx); - if (retval) { - CX18_ERR("Error %d setting up streams\n", retval); - goto free_irq; - } - retval = cx18_streams_register(cx); - if (retval) { - CX18_ERR("Error %d registering devices\n", retval); - goto free_streams; - } - - CX18_INFO("Initialized card: %s\n", cx->card_name); - - /* Load cx18 submodules (cx18-alsa) */ - request_modules(cx); - return 0; - -free_streams: - cx18_streams_cleanup(cx, 1); -free_irq: - free_irq(cx->pci_dev->irq, (void *)cx); -free_i2c: - exit_cx18_i2c(cx); -free_map: - cx18_iounmap(cx); -free_mem: - release_mem_region(cx->base_addr, CX18_MEM_SIZE); -free_workqueues: - destroy_workqueue(cx->in_work_queue); -err: - if (retval == 0) - retval = -ENODEV; - CX18_ERR("Error %d on initialization\n", retval); - - v4l2_device_unregister(&cx->v4l2_dev); - kfree(cx); - return retval; -} - -int cx18_init_on_first_open(struct cx18 *cx) -{ - int video_input; - int fw_retry_count = 3; - struct v4l2_frequency vf; - struct cx18_open_id fh; - v4l2_std_id std; - - fh.cx = cx; - - if (test_bit(CX18_F_I_FAILED, &cx->i_flags)) - return -ENXIO; - - if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags)) - return 0; - - while (--fw_retry_count > 0) { - /* load firmware */ - if (cx18_firmware_init(cx) == 0) - break; - if (fw_retry_count > 1) - CX18_WARN("Retry loading firmware\n"); - } - - if (fw_retry_count == 0) { - set_bit(CX18_F_I_FAILED, &cx->i_flags); - return -ENXIO; - } - set_bit(CX18_F_I_LOADED_FW, &cx->i_flags); - - /* - * Init the firmware twice to work around a silicon bug - * with the digital TS. - * - * The second firmware load requires us to normalize the APU state, - * or the audio for the first analog capture will be badly incorrect. - * - * I can't seem to call APU_RESETAI and have it succeed without the - * APU capturing audio, so we start and stop it here to do the reset - */ - - /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ - cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); - cx18_vapi(cx, CX18_APU_RESETAI, 0); - cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); - - fw_retry_count = 3; - while (--fw_retry_count > 0) { - /* load firmware */ - if (cx18_firmware_init(cx) == 0) - break; - if (fw_retry_count > 1) - CX18_WARN("Retry loading firmware\n"); - } - - if (fw_retry_count == 0) { - set_bit(CX18_F_I_FAILED, &cx->i_flags); - return -ENXIO; - } - - /* - * The second firmware load requires us to normalize the APU state, - * or the audio for the first analog capture will be badly incorrect. - * - * I can't seem to call APU_RESETAI and have it succeed without the - * APU capturing audio, so we start and stop it here to do the reset - */ - - /* MPEG Encoding, 224 kbps, MPEG Layer II, 48 ksps */ - cx18_vapi(cx, CX18_APU_START, 2, CX18_APU_ENCODING_METHOD_MPEG|0xb9, 0); - cx18_vapi(cx, CX18_APU_RESETAI, 0); - cx18_vapi(cx, CX18_APU_STOP, 1, CX18_APU_ENCODING_METHOD_MPEG); - - /* Init the A/V decoder, if it hasn't been already */ - v4l2_subdev_call(cx->sd_av, core, load_fw); - - vf.tuner = 0; - vf.type = V4L2_TUNER_ANALOG_TV; - vf.frequency = 6400; /* the tuner 'baseline' frequency */ - - /* Set initial frequency. For PAL/SECAM broadcasts no - 'default' channel exists AFAIK. */ - if (cx->std == V4L2_STD_NTSC_M_JP) - vf.frequency = 1460; /* ch. 1 91250*16/1000 */ - else if (cx->std & V4L2_STD_NTSC_M) - vf.frequency = 1076; /* ch. 4 67250*16/1000 */ - - video_input = cx->active_input; - cx->active_input++; /* Force update of input */ - cx18_s_input(NULL, &fh, video_input); - - /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code - in one place. */ - cx->std++; /* Force full standard initialization */ - std = (cx->tuner_std == V4L2_STD_ALL) ? V4L2_STD_NTSC_M : cx->tuner_std; - cx18_s_std(NULL, &fh, &std); - cx18_s_frequency(NULL, &fh, &vf); - return 0; -} - -static void cx18_cancel_in_work_orders(struct cx18 *cx) -{ - int i; - for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) - cancel_work_sync(&cx->in_work_order[i].work); -} - -static void cx18_cancel_out_work_orders(struct cx18 *cx) -{ - int i; - for (i = 0; i < CX18_MAX_STREAMS; i++) - if (&cx->streams[i].video_dev != NULL) - cancel_work_sync(&cx->streams[i].out_work_order); -} - -static void cx18_remove(struct pci_dev *pci_dev) -{ - struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); - struct cx18 *cx = to_cx18(v4l2_dev); - int i; - - CX18_DEBUG_INFO("Removing Card\n"); - - flush_request_modules(cx); - - /* Stop all captures */ - CX18_DEBUG_INFO("Stopping all streams\n"); - if (atomic_read(&cx->tot_capturing) > 0) - cx18_stop_all_captures(cx); - - /* Stop interrupts that cause incoming work to be queued */ - cx18_sw1_irq_disable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); - - /* Incoming work can cause outgoing work, so clean up incoming first */ - cx18_cancel_in_work_orders(cx); - cx18_cancel_out_work_orders(cx); - - /* Stop ack interrupts that may have been needed for work to finish */ - cx18_sw2_irq_disable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); - - cx18_halt_firmware(cx); - - destroy_workqueue(cx->in_work_queue); - - cx18_streams_cleanup(cx, 1); - - exit_cx18_i2c(cx); - - free_irq(cx->pci_dev->irq, (void *)cx); - - cx18_iounmap(cx); - - release_mem_region(cx->base_addr, CX18_MEM_SIZE); - - pci_disable_device(cx->pci_dev); - - if (cx->vbi.sliced_mpeg_data[0] != NULL) - for (i = 0; i < CX18_VBI_FRAMES; i++) - kfree(cx->vbi.sliced_mpeg_data[i]); - - v4l2_ctrl_handler_free(&cx->av_state.hdl); - - CX18_INFO("Removed %s\n", cx->card_name); - - v4l2_device_unregister(v4l2_dev); - kfree(cx); -} - - -/* define a pci_driver for card detection */ -static struct pci_driver cx18_pci_driver = { - .name = "cx18", - .id_table = cx18_pci_tbl, - .probe = cx18_probe, - .remove = cx18_remove, -}; - -static int __init module_start(void) -{ - printk(KERN_INFO "cx18: Start initialization, version %s\n", - CX18_VERSION); - - /* Validate parameters */ - if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) { - printk(KERN_ERR "cx18: Exiting, cx18_first_minor must be between 0 and %d\n", - CX18_MAX_CARDS - 1); - return -1; - } - - if (cx18_debug < 0 || cx18_debug > 511) { - cx18_debug = 0; - printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n"); - } - - if (pci_register_driver(&cx18_pci_driver)) { - printk(KERN_ERR "cx18: Error detecting PCI card\n"); - return -ENODEV; - } - printk(KERN_INFO "cx18: End initialization\n"); - return 0; -} - -static void __exit module_cleanup(void) -{ - pci_unregister_driver(&cx18_pci_driver); -} - -module_init(module_start); -module_exit(module_cleanup); -MODULE_FIRMWARE(XC2028_DEFAULT_FIRMWARE); diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h deleted file mode 100644 index 2767c64df0c..00000000000 --- a/drivers/media/video/cx18/cx18-driver.h +++ /dev/null @@ -1,730 +0,0 @@ -/* - * cx18 driver internal defines and structures - * - * Derived from ivtv-driver.h - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#ifndef CX18_DRIVER_H -#define CX18_DRIVER_H - -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/sched.h> -#include <linux/fs.h> -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> -#include <linux/list.h> -#include <linux/unistd.h> -#include <linux/pagemap.h> -#include <linux/workqueue.h> -#include <linux/mutex.h> -#include <linux/slab.h> -#include <asm/byteorder.h> - -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-device.h> -#include <media/v4l2-fh.h> -#include <media/tuner.h> -#include <media/ir-kbd-i2c.h> -#include "cx18-mailbox.h" -#include "cx18-av-core.h" -#include "cx23418.h" - -/* DVB */ -#include "demux.h" -#include "dmxdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_net.h" -#include "dvbdev.h" - -/* Videobuf / YUV support */ -#include <media/videobuf-core.h> -#include <media/videobuf-vmalloc.h> - -#ifndef CONFIG_PCI -# error "This driver requires kernel PCI support." -#endif - -#define CX18_MEM_OFFSET 0x00000000 -#define CX18_MEM_SIZE 0x04000000 -#define CX18_REG_OFFSET 0x02000000 - -/* Maximum cx18 driver instances. */ -#define CX18_MAX_CARDS 32 - -/* Supported cards */ -#define CX18_CARD_HVR_1600_ESMT 0 /* Hauppauge HVR 1600 (ESMT memory) */ -#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */ -#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */ -#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */ -#define CX18_CARD_CNXT_RAPTOR_PAL 4 /* Conexant Raptor PAL */ -#define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/ -#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */ -#define CX18_CARD_LEADTEK_DVR3100H 7 /* Leadtek WinFast DVR3100 H */ -#define CX18_CARD_GOTVIEW_PCI_DVD3 8 /* GoTView PCI DVD3 Hybrid */ -#define CX18_CARD_HVR_1600_S5H1411 9 /* Hauppauge HVR 1600 s5h1411/tda18271*/ -#define CX18_CARD_LAST 9 - -#define CX18_ENC_STREAM_TYPE_MPG 0 -#define CX18_ENC_STREAM_TYPE_TS 1 -#define CX18_ENC_STREAM_TYPE_YUV 2 -#define CX18_ENC_STREAM_TYPE_VBI 3 -#define CX18_ENC_STREAM_TYPE_PCM 4 -#define CX18_ENC_STREAM_TYPE_IDX 5 -#define CX18_ENC_STREAM_TYPE_RAD 6 -#define CX18_MAX_STREAMS 7 - -/* system vendor and device IDs */ -#define PCI_VENDOR_ID_CX 0x14f1 -#define PCI_DEVICE_ID_CX23418 0x5b7a - -/* subsystem vendor ID */ -#define CX18_PCI_ID_HAUPPAUGE 0x0070 -#define CX18_PCI_ID_COMPRO 0x185b -#define CX18_PCI_ID_YUAN 0x12ab -#define CX18_PCI_ID_CONEXANT 0x14f1 -#define CX18_PCI_ID_TOSHIBA 0x1179 -#define CX18_PCI_ID_LEADTEK 0x107D -#define CX18_PCI_ID_GOTVIEW 0x5854 - -/* ======================================================================== */ -/* ========================== START USER SETTABLE DMA VARIABLES =========== */ -/* ======================================================================== */ - -/* DMA Buffers, Default size in MB allocated */ -#define CX18_DEFAULT_ENC_TS_BUFFERS 1 -#define CX18_DEFAULT_ENC_MPG_BUFFERS 2 -#define CX18_DEFAULT_ENC_IDX_BUFFERS 1 -#define CX18_DEFAULT_ENC_YUV_BUFFERS 2 -#define CX18_DEFAULT_ENC_VBI_BUFFERS 1 -#define CX18_DEFAULT_ENC_PCM_BUFFERS 1 - -/* Maximum firmware DMA buffers per stream */ -#define CX18_MAX_FW_MDLS_PER_STREAM 63 - -/* YUV buffer sizes in bytes to ensure integer # of frames per buffer */ -#define CX18_UNIT_ENC_YUV_BUFSIZE (720 * 32 * 3 / 2) /* bytes */ -#define CX18_625_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 576/32) -#define CX18_525_LINE_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 480/32) - -/* IDX buffer size should be a multiple of the index entry size from the chip */ -struct cx18_enc_idx_entry { - __le32 length; - __le32 offset_low; - __le32 offset_high; - __le32 flags; - __le32 pts_low; - __le32 pts_high; -} __attribute__ ((packed)); -#define CX18_UNIT_ENC_IDX_BUFSIZE \ - (sizeof(struct cx18_enc_idx_entry) * V4L2_ENC_IDX_ENTRIES) - -/* DMA buffer, default size in kB allocated */ -#define CX18_DEFAULT_ENC_TS_BUFSIZE 32 -#define CX18_DEFAULT_ENC_MPG_BUFSIZE 32 -#define CX18_DEFAULT_ENC_IDX_BUFSIZE (CX18_UNIT_ENC_IDX_BUFSIZE * 1 / 1024 + 1) -#define CX18_DEFAULT_ENC_YUV_BUFSIZE (CX18_UNIT_ENC_YUV_BUFSIZE * 3 / 1024 + 1) -#define CX18_DEFAULT_ENC_PCM_BUFSIZE 4 - -/* i2c stuff */ -#define I2C_CLIENTS_MAX 16 - -/* debugging */ - -/* Flag to turn on high volume debugging */ -#define CX18_DBGFLG_WARN (1 << 0) -#define CX18_DBGFLG_INFO (1 << 1) -#define CX18_DBGFLG_API (1 << 2) -#define CX18_DBGFLG_DMA (1 << 3) -#define CX18_DBGFLG_IOCTL (1 << 4) -#define CX18_DBGFLG_FILE (1 << 5) -#define CX18_DBGFLG_I2C (1 << 6) -#define CX18_DBGFLG_IRQ (1 << 7) -/* Flag to turn on high volume debugging */ -#define CX18_DBGFLG_HIGHVOL (1 << 8) - -/* NOTE: extra space before comma in 'fmt , ## args' is required for - gcc-2.95, otherwise it won't compile. */ -#define CX18_DEBUG(x, type, fmt, args...) \ - do { \ - if ((x) & cx18_debug) \ - v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \ - } while (0) -#define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args) -#define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args) -#define CX18_DEBUG_API(fmt, args...) CX18_DEBUG(CX18_DBGFLG_API, "api", fmt , ## args) -#define CX18_DEBUG_DMA(fmt, args...) CX18_DEBUG(CX18_DBGFLG_DMA, "dma", fmt , ## args) -#define CX18_DEBUG_IOCTL(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define CX18_DEBUG_FILE(fmt, args...) CX18_DEBUG(CX18_DBGFLG_FILE, "file", fmt , ## args) -#define CX18_DEBUG_I2C(fmt, args...) CX18_DEBUG(CX18_DBGFLG_I2C, "i2c", fmt , ## args) -#define CX18_DEBUG_IRQ(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IRQ, "irq", fmt , ## args) - -#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \ - do { \ - if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \ - v4l2_info(&cx->v4l2_dev, " " type ": " fmt , ## args); \ - } while (0) -#define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args) -#define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args) -#define CX18_DEBUG_HI_API(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_API, "api", fmt , ## args) -#define CX18_DEBUG_HI_DMA(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_DMA, "dma", fmt , ## args) -#define CX18_DEBUG_HI_IOCTL(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args) -#define CX18_DEBUG_HI_FILE(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_FILE, "file", fmt , ## args) -#define CX18_DEBUG_HI_I2C(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_I2C, "i2c", fmt , ## args) -#define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args) - -/* Standard kernel messages */ -#define CX18_ERR(fmt, args...) v4l2_err(&cx->v4l2_dev, fmt , ## args) -#define CX18_WARN(fmt, args...) v4l2_warn(&cx->v4l2_dev, fmt , ## args) -#define CX18_INFO(fmt, args...) v4l2_info(&cx->v4l2_dev, fmt , ## args) - -/* Messages for internal subdevs to use */ -#define CX18_DEBUG_DEV(x, dev, type, fmt, args...) \ - do { \ - if ((x) & cx18_debug) \ - v4l2_info(dev, " " type ": " fmt , ## args); \ - } while (0) -#define CX18_DEBUG_WARN_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args) -#define CX18_DEBUG_INFO_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args) -#define CX18_DEBUG_API_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args) -#define CX18_DEBUG_DMA_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args) -#define CX18_DEBUG_IOCTL_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args) -#define CX18_DEBUG_FILE_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args) -#define CX18_DEBUG_I2C_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args) -#define CX18_DEBUG_IRQ_DEV(dev, fmt, args...) \ - CX18_DEBUG_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args) - -#define CX18_DEBUG_HIGH_VOL_DEV(x, dev, type, fmt, args...) \ - do { \ - if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \ - v4l2_info(dev, " " type ": " fmt , ## args); \ - } while (0) -#define CX18_DEBUG_HI_WARN_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_WARN, dev, "warning", fmt , ## args) -#define CX18_DEBUG_HI_INFO_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_INFO, dev, "info", fmt , ## args) -#define CX18_DEBUG_HI_API_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_API, dev, "api", fmt , ## args) -#define CX18_DEBUG_HI_DMA_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_DMA, dev, "dma", fmt , ## args) -#define CX18_DEBUG_HI_IOCTL_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IOCTL, dev, "ioctl", fmt , ## args) -#define CX18_DEBUG_HI_FILE_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_FILE, dev, "file", fmt , ## args) -#define CX18_DEBUG_HI_I2C_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_I2C, dev, "i2c", fmt , ## args) -#define CX18_DEBUG_HI_IRQ_DEV(dev, fmt, args...) \ - CX18_DEBUG_HIGH_VOL_DEV(CX18_DBGFLG_IRQ, dev, "irq", fmt , ## args) - -#define CX18_ERR_DEV(dev, fmt, args...) v4l2_err(dev, fmt , ## args) -#define CX18_WARN_DEV(dev, fmt, args...) v4l2_warn(dev, fmt , ## args) -#define CX18_INFO_DEV(dev, fmt, args...) v4l2_info(dev, fmt , ## args) - -extern int cx18_debug; - -struct cx18_options { - int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */ - int cardtype; /* force card type on load */ - int tuner; /* set tuner on load */ - int radio; /* enable/disable radio */ -}; - -/* per-mdl bit flags */ -#define CX18_F_M_NEED_SWAP 0 /* mdl buffer data must be endianess swapped */ - -/* per-stream, s_flags */ -#define CX18_F_S_CLAIMED 3 /* this stream is claimed */ -#define CX18_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */ -#define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */ -#define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */ -#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */ -#define CX18_F_S_STOPPING 9 /* telling the fw to stop capturing */ - -/* per-cx18, i_flags */ -#define CX18_F_I_LOADED_FW 0 /* Loaded firmware 1st time */ -#define CX18_F_I_EOS 4 /* End of encoder stream */ -#define CX18_F_I_RADIO_USER 5 /* radio tuner is selected */ -#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */ -#define CX18_F_I_INITED 21 /* set after first open */ -#define CX18_F_I_FAILED 22 /* set if first open failed */ - -/* These are the VBI types as they appear in the embedded VBI private packets. */ -#define CX18_SLICED_TYPE_TELETEXT_B (1) -#define CX18_SLICED_TYPE_CAPTION_525 (4) -#define CX18_SLICED_TYPE_WSS_625 (5) -#define CX18_SLICED_TYPE_VPS (7) - -/** - * list_entry_is_past_end - check if a previous loop cursor is off list end - * @pos: the type * previously used as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * Check if the entry's list_head is the head of the list, thus it's not a - * real entry but was the loop cursor that walked past the end - */ -#define list_entry_is_past_end(pos, head, member) \ - (&pos->member == (head)) - -struct cx18_buffer { - struct list_head list; - dma_addr_t dma_handle; - char *buf; - - u32 bytesused; - u32 readpos; -}; - -struct cx18_mdl { - struct list_head list; - u32 id; /* index into cx->scb->cpu_mdl[] of 1st cx18_mdl_ent */ - - unsigned int skipped; - unsigned long m_flags; - - struct list_head buf_list; - struct cx18_buffer *curr_buf; /* current buffer in list for reading */ - - u32 bytesused; - u32 readpos; -}; - -struct cx18_queue { - struct list_head list; - atomic_t depth; - u32 bytesused; - spinlock_t lock; -}; - -struct cx18_stream; /* forward reference */ - -struct cx18_dvb { - struct cx18_stream *stream; - struct dmx_frontend hw_frontend; - struct dmx_frontend mem_frontend; - struct dmxdev dmxdev; - struct dvb_adapter dvb_adapter; - struct dvb_demux demux; - struct dvb_frontend *fe; - struct dvb_net dvbnet; - int enabled; - int feeding; - struct mutex feedlock; -}; - -struct cx18; /* forward reference */ -struct cx18_scb; /* forward reference */ - - -#define CX18_MAX_MDL_ACKS 2 -#define CX18_MAX_IN_WORK_ORDERS (CX18_MAX_FW_MDLS_PER_STREAM + 7) -/* CPU_DE_RELEASE_MDL can burst CX18_MAX_FW_MDLS_PER_STREAM orders in a group */ - -#define CX18_F_EWO_MB_STALE_UPON_RECEIPT 0x1 -#define CX18_F_EWO_MB_STALE_WHILE_PROC 0x2 -#define CX18_F_EWO_MB_STALE \ - (CX18_F_EWO_MB_STALE_UPON_RECEIPT | CX18_F_EWO_MB_STALE_WHILE_PROC) - -struct cx18_in_work_order { - struct work_struct work; - atomic_t pending; - struct cx18 *cx; - unsigned long flags; - int rpu; - struct cx18_mailbox mb; - struct cx18_mdl_ack mdl_ack[CX18_MAX_MDL_ACKS]; - char *str; -}; - -#define CX18_INVALID_TASK_HANDLE 0xffffffff - -struct cx18_stream { - /* These first five fields are always set, even if the stream - is not actually created. */ - struct video_device *video_dev; /* NULL when stream not created */ - struct cx18_dvb *dvb; /* DVB / Digital Transport */ - struct cx18 *cx; /* for ease of use */ - const char *name; /* name of the stream */ - int type; /* stream type */ - u32 handle; /* task handle */ - unsigned int mdl_base_idx; - - u32 id; - unsigned long s_flags; /* status flags, see above */ - int dma; /* can be PCI_DMA_TODEVICE, - PCI_DMA_FROMDEVICE or - PCI_DMA_NONE */ - wait_queue_head_t waitq; - - /* Buffers */ - struct list_head buf_pool; /* buffers not attached to an MDL */ - u32 buffers; /* total buffers owned by this stream */ - u32 buf_size; /* size in bytes of a single buffer */ - - /* MDL sizes - all stream MDLs are the same size */ - u32 bufs_per_mdl; - u32 mdl_size; /* total bytes in all buffers in a mdl */ - - /* MDL Queues */ - struct cx18_queue q_free; /* free - in rotation, not committed */ - struct cx18_queue q_busy; /* busy - in use by firmware */ - struct cx18_queue q_full; /* full - data for user apps */ - struct cx18_queue q_idle; /* idle - not in rotation */ - - struct work_struct out_work_order; - - /* Videobuf for YUV video */ - u32 pixelformat; - u32 vb_bytes_per_frame; - struct list_head vb_capture; /* video capture queue */ - spinlock_t vb_lock; - struct timer_list vb_timeout; - - struct videobuf_queue vbuf_q; - spinlock_t vbuf_q_lock; /* Protect vbuf_q */ - enum v4l2_buf_type vb_type; -}; - -struct cx18_videobuf_buffer { - /* Common video buffer sub-system struct */ - struct videobuf_buffer vb; - v4l2_std_id tvnorm; /* selected tv norm */ - u32 bytes_used; -}; - -struct cx18_open_id { - struct v4l2_fh fh; - u32 open_id; - int type; - struct cx18 *cx; -}; - -static inline struct cx18_open_id *fh2id(struct v4l2_fh *fh) -{ - return container_of(fh, struct cx18_open_id, fh); -} - -static inline struct cx18_open_id *file2id(struct file *file) -{ - return fh2id(file->private_data); -} - -/* forward declaration of struct defined in cx18-cards.h */ -struct cx18_card; - -/* - * A note about "sliced" VBI data as implemented in this driver: - * - * Currently we collect the sliced VBI in the form of Ancillary Data - * packets, inserted by the AV core decoder/digitizer/slicer in the - * horizontal blanking region of the VBI lines, in "raw" mode as far as - * the Encoder is concerned. We don't ever tell the Encoder itself - * to provide sliced VBI. (AV Core: sliced mode - Encoder: raw mode) - * - * We then process the ancillary data ourselves to send the sliced data - * to the user application directly or build up MPEG-2 private stream 1 - * packets to splice into (only!) MPEG-2 PS streams for the user app. - * - * (That's how ivtv essentially does it.) - * - * The Encoder should be able to extract certain sliced VBI data for - * us and provide it in a separate stream or splice it into any type of - * MPEG PS or TS stream, but this isn't implemented yet. - */ - -/* - * Number of "raw" VBI samples per horizontal line we tell the Encoder to - * grab from the decoder/digitizer/slicer output for raw or sliced VBI. - * It depends on the pixel clock and the horiz rate: - * - * (1/Fh)*(2*Fp) = Samples/line - * = 4 bytes EAV + Anc data in hblank + 4 bytes SAV + active samples - * - * Sliced VBI data is sent as ancillary data during horizontal blanking - * Raw VBI is sent as active video samples during vertcal blanking - * - * We use a BT.656 pxiel clock of 13.5 MHz and a BT.656 active line - * length of 720 pixels @ 4:2:2 sampling. Thus... - * - * For systems that use a 15.734 kHz horizontal rate, such as - * NTSC-M, PAL-M, PAL-60, and other 60 Hz/525 line systems, we have: - * - * (1/15.734 kHz) * 2 * 13.5 MHz = 1716 samples/line = - * 4 bytes SAV + 268 bytes anc data + 4 bytes SAV + 1440 active samples - * - * For systems that use a 15.625 kHz horizontal rate, such as - * PAL-B/G/H, PAL-I, SECAM-L and other 50 Hz/625 line systems, we have: - * - * (1/15.625 kHz) * 2 * 13.5 MHz = 1728 samples/line = - * 4 bytes SAV + 280 bytes anc data + 4 bytes SAV + 1440 active samples - */ -static const u32 vbi_active_samples = 1444; /* 4 byte SAV + 720 Y + 720 U/V */ -static const u32 vbi_hblank_samples_60Hz = 272; /* 4 byte EAV + 268 anc/fill */ -static const u32 vbi_hblank_samples_50Hz = 284; /* 4 byte EAV + 280 anc/fill */ - -#define CX18_VBI_FRAMES 32 - -struct vbi_info { - /* Current state of v4l2 VBI settings for this device */ - struct v4l2_format in; - struct v4l2_sliced_vbi_format *sliced_in; /* pointer to in.fmt.sliced */ - u32 count; /* Count of VBI data lines: 60 Hz: 12 or 50 Hz: 18 */ - u32 start[2]; /* First VBI data line per field: 10 & 273 or 6 & 318 */ - - u32 frame; /* Count of VBI buffers/frames received from Encoder */ - - /* - * Vars for creation and insertion of MPEG Private Stream 1 packets - * of sliced VBI data into an MPEG PS - */ - - /* Boolean: create and insert Private Stream 1 packets into the PS */ - int insert_mpeg; - - /* - * Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines. - * Used in cx18-vbi.c only for collecting sliced data, and as a source - * during conversion of sliced VBI data into MPEG Priv Stream 1 packets. - * We don't need to save state here, but the array may have been a bit - * too big (2304 bytes) to alloc from the stack. - */ - struct v4l2_sliced_vbi_data sliced_data[36]; - - /* - * A ring buffer of driver-generated MPEG-2 PS - * Program Pack/Private Stream 1 packets for sliced VBI data insertion - * into the MPEG PS stream. - * - * In each sliced_mpeg_data[] buffer is: - * 16 byte MPEG-2 PS Program Pack Header - * 16 byte MPEG-2 Private Stream 1 PES Header - * 4 byte magic number: "itv0" or "ITV0" - * 4 byte first field line mask, if "itv0" - * 4 byte second field line mask, if "itv0" - * 36 lines, if "ITV0"; or <36 lines, if "itv0"; of sliced VBI data - * - * Each line in the payload is - * 1 byte line header derived from the SDID (WSS, CC, VPS, etc.) - * 42 bytes of line data - * - * That's a maximum 1552 bytes of payload in the Private Stream 1 packet - * which is the payload size a PVR-350 (CX23415) MPEG decoder will - * accept for VBI data. So, including the headers, it's a maximum 1584 - * bytes total. - */ -#define CX18_SLICED_MPEG_DATA_MAXSZ 1584 - /* copy_vbi_buf() needs 8 temp bytes on the end for the worst case */ -#define CX18_SLICED_MPEG_DATA_BUFSZ (CX18_SLICED_MPEG_DATA_MAXSZ+8) - u8 *sliced_mpeg_data[CX18_VBI_FRAMES]; - u32 sliced_mpeg_size[CX18_VBI_FRAMES]; - - /* Count of Program Pack/Program Stream 1 packets inserted into PS */ - u32 inserted_frame; - - /* - * A dummy driver stream transfer mdl & buffer with a copy of the next - * sliced_mpeg_data[] buffer for output to userland apps. - * Only used in cx18-fileops.c, but its state needs to persist at times. - */ - struct cx18_mdl sliced_mpeg_mdl; - struct cx18_buffer sliced_mpeg_buf; -}; - -/* Per cx23418, per I2C bus private algo callback data */ -struct cx18_i2c_algo_callback_data { - struct cx18 *cx; - int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */ -}; - -#define CX18_MAX_MMIO_WR_RETRIES 10 - -/* Struct to hold info about cx18 cards */ -struct cx18 { - int instance; - struct pci_dev *pci_dev; - struct v4l2_device v4l2_dev; - struct v4l2_subdev *sd_av; /* A/V decoder/digitizer sub-device */ - struct v4l2_subdev *sd_extmux; /* External multiplexer sub-dev */ - - const struct cx18_card *card; /* card information */ - const char *card_name; /* full name of the card */ - const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */ - u8 is_50hz; - u8 is_60hz; - u8 nof_inputs; /* number of video inputs */ - u8 nof_audio_inputs; /* number of audio inputs */ - u32 v4l2_cap; /* V4L2 capabilities of card */ - u32 hw_flags; /* Hardware description of the board */ - unsigned int free_mdl_idx; - struct cx18_scb __iomem *scb; /* pointer to SCB */ - struct mutex epu2apu_mb_lock; /* protect driver to chip mailbox in SCB*/ - struct mutex epu2cpu_mb_lock; /* protect driver to chip mailbox in SCB*/ - - struct cx18_av_state av_state; - - /* codec settings */ - struct cx2341x_handler cxhdl; - u32 filter_mode; - u32 temporal_strength; - u32 spatial_strength; - - /* dualwatch */ - unsigned long dualwatch_jiffies; - u32 dualwatch_stereo_mode; - - struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */ - struct cx18_options options; /* User options */ - int stream_buffers[CX18_MAX_STREAMS]; /* # of buffers for each stream */ - int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */ - struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */ - struct snd_cx18_card *alsa; /* ALSA interface for PCM capture stream */ - void (*pcm_announce_callback)(struct snd_cx18_card *card, u8 *pcm_data, - size_t num_bytes); - - unsigned long i_flags; /* global cx18 flags */ - atomic_t ana_capturing; /* count number of active analog capture streams */ - atomic_t tot_capturing; /* total count number of active capture streams */ - int search_pack_header; - - int open_id; /* incremented each time an open occurs, used as - unique ID. Starts at 1, so 0 can be used as - uninitialized value in the stream->id. */ - - resource_size_t base_addr; - - u8 card_rev; - void __iomem *enc_mem, *reg_mem; - - struct vbi_info vbi; - - u64 mpg_data_received; - u64 vbi_data_inserted; - - wait_queue_head_t mb_apu_waitq; - wait_queue_head_t mb_cpu_waitq; - wait_queue_head_t cap_w; - /* when the current DMA is finished this queue is woken up */ - wait_queue_head_t dma_waitq; - - u32 sw1_irq_mask; - u32 sw2_irq_mask; - u32 hw2_irq_mask; - - struct workqueue_struct *in_work_queue; - char in_workq_name[11]; /* "cx18-NN-in" */ - struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS]; - char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */ - - /* i2c */ - struct i2c_adapter i2c_adap[2]; - struct i2c_algo_bit_data i2c_algo[2]; - struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2]; - - struct IR_i2c_init_data ir_i2c_init_data; - - /* gpio */ - u32 gpio_dir; - u32 gpio_val; - struct mutex gpio_lock; - struct v4l2_subdev sd_gpiomux; - struct v4l2_subdev sd_resetctrl; - - /* v4l2 and User settings */ - - /* codec settings */ - u32 audio_input; - u32 active_input; - v4l2_std_id std; - v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */ - - /* Used for cx18-alsa module loading */ - struct work_struct request_module_wk; -}; - -static inline struct cx18 *to_cx18(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct cx18, v4l2_dev); -} - -/* cx18 extensions to be loaded */ -extern int (*cx18_ext_init)(struct cx18 *); - -/* Globals */ -extern int cx18_first_minor; - -/*==============Prototypes==================*/ - -/* Return non-zero if a signal is pending */ -int cx18_msleep_timeout(unsigned int msecs, int intr); - -/* Read Hauppauge eeprom */ -struct tveeprom; /* forward reference */ -void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv); - -/* First-open initialization: load firmware, etc. */ -int cx18_init_on_first_open(struct cx18 *cx); - -/* Test if the current VBI mode is raw (1) or sliced (0) */ -static inline int cx18_raw_vbi(const struct cx18 *cx) -{ - return cx->vbi.in.type == V4L2_BUF_TYPE_VBI_CAPTURE; -} - -/* Call the specified callback for all subdevs with a grp_id bit matching the - * mask in hw (if 0, then match them all). Ignore any errors. */ -#define cx18_call_hw(cx, hw, o, f, args...) \ - do { \ - struct v4l2_subdev *__sd; \ - __v4l2_device_call_subdevs_p(&(cx)->v4l2_dev, __sd, \ - !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \ - } while (0) - -#define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args) - -/* Call the specified callback for all subdevs with a grp_id bit matching the - * mask in hw (if 0, then match them all). If the callback returns an error - * other than 0 or -ENOIOCTLCMD, then return with that error code. */ -#define cx18_call_hw_err(cx, hw, o, f, args...) \ -({ \ - struct v4l2_subdev *__sd; \ - __v4l2_device_call_subdevs_until_err_p(&(cx)->v4l2_dev, \ - __sd, !(hw) || (__sd->grp_id & (hw)), o, f, \ - ##args); \ -}) - -#define cx18_call_all_err(cx, o, f, args...) \ - cx18_call_hw_err(cx, 0, o, f , ##args) - -#endif /* CX18_DRIVER_H */ diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c deleted file mode 100644 index 3eac59c5123..00000000000 --- a/drivers/media/video/cx18/cx18-dvb.c +++ /dev/null @@ -1,609 +0,0 @@ -/* - * cx18 functions for DVB support - * - * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cx18-version.h" -#include "cx18-dvb.h" -#include "cx18-io.h" -#include "cx18-queue.h" -#include "cx18-streams.h" -#include "cx18-cards.h" -#include "cx18-gpio.h" -#include "s5h1409.h" -#include "mxl5005s.h" -#include "s5h1411.h" -#include "tda18271.h" -#include "zl10353.h" - -#include <linux/firmware.h> -#include "mt352.h" -#include "mt352_priv.h" -#include "tuner-xc2028.h" - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define FWFILE "dvb-cx18-mpc718-mt352.fw" - -#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000 -#define CX18_CLOCK_ENABLE2 0xc71024 -#define CX18_DMUX_CLK_MASK 0x0080 - -/* - * CX18_CARD_HVR_1600_ESMT - * CX18_CARD_HVR_1600_SAMSUNG - */ - -static struct mxl5005s_config hauppauge_hvr1600_tuner = { - .i2c_address = 0xC6 >> 1, - .if_freq = IF_FREQ_5380000HZ, - .xtal_freq = CRYSTAL_FREQ_16000000HZ, - .agc_mode = MXL_SINGLE_AGC, - .tracking_filter = MXL_TF_C_H, - .rssi_enable = MXL_RSSI_ENABLE, - .cap_select = MXL_CAP_SEL_ENABLE, - .div_out = MXL_DIV_OUT_4, - .clock_out = MXL_CLOCK_OUT_DISABLE, - .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, - .top = MXL5005S_TOP_25P2, - .mod_mode = MXL_DIGITAL_MODE, - .if_mode = MXL_ZERO_IF, - .qam_gain = 0x02, - .AgcMasterByte = 0x00, -}; - -static struct s5h1409_config hauppauge_hvr1600_config = { - .demod_address = 0x32 >> 1, - .output_mode = S5H1409_SERIAL_OUTPUT, - .gpio = S5H1409_GPIO_ON, - .qam_if = 44000, - .inversion = S5H1409_INVERSION_OFF, - .status_mode = S5H1409_DEMODLOCKING, - .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, - .hvr1600_opt = S5H1409_HVR1600_OPTIMIZE -}; - -/* - * CX18_CARD_HVR_1600_S5H1411 - */ -static struct s5h1411_config hcw_s5h1411_config = { - .output_mode = S5H1411_SERIAL_OUTPUT, - .gpio = S5H1411_GPIO_OFF, - .vsb_if = S5H1411_IF_44000, - .qam_if = S5H1411_IF_4000, - .inversion = S5H1411_INVERSION_ON, - .status_mode = S5H1411_DEMODLOCKING, - .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK, -}; - -static struct tda18271_std_map hauppauge_tda18271_std_map = { - .atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3, - .if_lvl = 6, .rfagc_top = 0x37 }, - .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0, - .if_lvl = 6, .rfagc_top = 0x37 }, -}; - -static struct tda18271_config hauppauge_tda18271_config = { - .std_map = &hauppauge_tda18271_std_map, - .gate = TDA18271_GATE_DIGITAL, - .output_opt = TDA18271_OUTPUT_LT_OFF, -}; - -/* - * CX18_CARD_LEADTEK_DVR3100H - */ -/* Information/confirmation of proper config values provided by Terry Wu */ -static struct zl10353_config leadtek_dvr3100h_demod = { - .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ - .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ - .parallel_ts = 1, /* Not a serial TS */ - .no_tuner = 1, /* XC3028 is not behind the gate */ - .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ -}; - -/* - * CX18_CARD_YUAN_MPC718 - */ -/* - * Due to - * - * 1. an absence of information on how to prgram the MT352 - * 2. the Linux mt352 module pushing MT352 initialzation off onto us here - * - * We have to use an init sequence that *you* must extract from the Windows - * driver (yuanrap.sys) and which we load as a firmware. - * - * If someone can provide me with a Zarlink MT352 (Intel CE6352?) Design Manual - * with chip programming details, then I can remove this annoyance. - */ -static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream, - const struct firmware **fw) -{ - struct cx18 *cx = stream->cx; - const char *fn = FWFILE; - int ret; - - ret = request_firmware(fw, fn, &cx->pci_dev->dev); - if (ret) - CX18_ERR("Unable to open firmware file %s\n", fn); - else { - size_t sz = (*fw)->size; - if (sz < 2 || sz > 64 || (sz % 2) != 0) { - CX18_ERR("Firmware %s has a bad size: %lu bytes\n", - fn, (unsigned long) sz); - ret = -EILSEQ; - release_firmware(*fw); - *fw = NULL; - } - } - - if (ret) { - CX18_ERR("The MPC718 board variant with the MT352 DVB-T" - "demodualtor will not work without it\n"); - CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware " - "mpc718' if you need the firmware\n"); - } - return ret; -} - -static int yuan_mpc718_mt352_init(struct dvb_frontend *fe) -{ - struct cx18_dvb *dvb = container_of(fe->dvb, - struct cx18_dvb, dvb_adapter); - struct cx18_stream *stream = dvb->stream; - const struct firmware *fw = NULL; - int ret; - int i; - u8 buf[3]; - - ret = yuan_mpc718_mt352_reqfw(stream, &fw); - if (ret) - return ret; - - /* Loop through all the register-value pairs in the firmware file */ - for (i = 0; i < fw->size; i += 2) { - buf[0] = fw->data[i]; - /* Intercept a few registers we want to set ourselves */ - switch (buf[0]) { - case TRL_NOMINAL_RATE_0: - /* Set our custom OFDM bandwidth in the case below */ - break; - case TRL_NOMINAL_RATE_1: - /* 6 MHz: 64/7 * 6/8 / 20.48 * 2^16 = 0x55b6.db6 */ - /* 7 MHz: 64/7 * 7/8 / 20.48 * 2^16 = 0x6400 */ - /* 8 MHz: 64/7 * 8/8 / 20.48 * 2^16 = 0x7249.249 */ - buf[1] = 0x72; - buf[2] = 0x49; - mt352_write(fe, buf, 3); - break; - case INPUT_FREQ_0: - /* Set our custom IF in the case below */ - break; - case INPUT_FREQ_1: - /* 4.56 MHz IF: (20.48 - 4.56)/20.48 * 2^14 = 0x31c0 */ - buf[1] = 0x31; - buf[2] = 0xc0; - mt352_write(fe, buf, 3); - break; - default: - /* Pass through the register-value pair from the fw */ - buf[1] = fw->data[i+1]; - mt352_write(fe, buf, 2); - break; - } - } - - buf[0] = (u8) TUNER_GO; - buf[1] = 0x01; /* Go */ - mt352_write(fe, buf, 2); - release_firmware(fw); - return 0; -} - -static struct mt352_config yuan_mpc718_mt352_demod = { - .demod_address = 0x1e >> 1, - .adc_clock = 20480, /* 20.480 MHz */ - .if2 = 4560, /* 4.560 MHz */ - .no_tuner = 1, /* XC3028 is not behind the gate */ - .demod_init = yuan_mpc718_mt352_init, -}; - -static struct zl10353_config yuan_mpc718_zl10353_demod = { - .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ - .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ - .parallel_ts = 1, /* Not a serial TS */ - .no_tuner = 1, /* XC3028 is not behind the gate */ - .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ -}; - -static struct zl10353_config gotview_dvd3_zl10353_demod = { - .demod_address = 0x1e >> 1, /* Datasheet suggested straps */ - .if2 = 45600, /* 4.560 MHz IF from the XC3028 */ - .parallel_ts = 1, /* Not a serial TS */ - .no_tuner = 1, /* XC3028 is not behind the gate */ - .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */ -}; - -static int dvb_register(struct cx18_stream *stream); - -/* Kernel DVB framework calls this when the feed needs to start. - * The CX18 framework should enable the transport DMA handling - * and queue processing. - */ -static int cx18_dvb_start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct cx18_stream *stream = (struct cx18_stream *) demux->priv; - struct cx18 *cx; - int ret; - u32 v; - - if (!stream) - return -EINVAL; - - cx = stream->cx; - CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n", - feed->pid, feed->index); - - mutex_lock(&cx->serialize_lock); - ret = cx18_init_on_first_open(cx); - mutex_unlock(&cx->serialize_lock); - if (ret) { - CX18_ERR("Failed to initialize firmware starting DVB feed\n"); - return ret; - } - ret = -EINVAL; - - switch (cx->card->type) { - case CX18_CARD_HVR_1600_ESMT: - case CX18_CARD_HVR_1600_SAMSUNG: - case CX18_CARD_HVR_1600_S5H1411: - v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL); - v |= 0x00400000; /* Serial Mode */ - v |= 0x00002000; /* Data Length - Byte */ - v |= 0x00010000; /* Error - Polarity */ - v |= 0x00020000; /* Error - Passthru */ - v |= 0x000c0000; /* Error - Ignore */ - cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL); - break; - - case CX18_CARD_LEADTEK_DVR3100H: - case CX18_CARD_YUAN_MPC718: - case CX18_CARD_GOTVIEW_PCI_DVD3: - default: - /* Assumption - Parallel transport - Signalling - * undefined or default. - */ - break; - } - - if (!demux->dmx.frontend) - return -EINVAL; - - mutex_lock(&stream->dvb->feedlock); - if (stream->dvb->feeding++ == 0) { - CX18_DEBUG_INFO("Starting Transport DMA\n"); - mutex_lock(&cx->serialize_lock); - set_bit(CX18_F_S_STREAMING, &stream->s_flags); - ret = cx18_start_v4l2_encode_stream(stream); - if (ret < 0) { - CX18_DEBUG_INFO("Failed to start Transport DMA\n"); - stream->dvb->feeding--; - if (stream->dvb->feeding == 0) - clear_bit(CX18_F_S_STREAMING, &stream->s_flags); - } - mutex_unlock(&cx->serialize_lock); - } else - ret = 0; - mutex_unlock(&stream->dvb->feedlock); - - return ret; -} - -/* Kernel DVB framework calls this when the feed needs to stop. */ -static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct cx18_stream *stream = (struct cx18_stream *)demux->priv; - struct cx18 *cx; - int ret = -EINVAL; - - if (stream) { - cx = stream->cx; - CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n", - feed->pid, feed->index); - - mutex_lock(&stream->dvb->feedlock); - if (--stream->dvb->feeding == 0) { - CX18_DEBUG_INFO("Stopping Transport DMA\n"); - mutex_lock(&cx->serialize_lock); - ret = cx18_stop_v4l2_encode_stream(stream, 0); - mutex_unlock(&cx->serialize_lock); - } else - ret = 0; - mutex_unlock(&stream->dvb->feedlock); - } - - return ret; -} - -int cx18_dvb_register(struct cx18_stream *stream) -{ - struct cx18 *cx = stream->cx; - struct cx18_dvb *dvb = stream->dvb; - struct dvb_adapter *dvb_adapter; - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - int ret; - - if (!dvb) - return -EINVAL; - - dvb->enabled = 0; - dvb->stream = stream; - - ret = dvb_register_adapter(&dvb->dvb_adapter, - CX18_DRIVER_NAME, - THIS_MODULE, &cx->pci_dev->dev, adapter_nr); - if (ret < 0) - goto err_out; - - dvb_adapter = &dvb->dvb_adapter; - - dvbdemux = &dvb->demux; - - dvbdemux->priv = (void *)stream; - - dvbdemux->filternum = 256; - dvbdemux->feednum = 256; - dvbdemux->start_feed = cx18_dvb_start_feed; - dvbdemux->stop_feed = cx18_dvb_stop_feed; - dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | - DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING); - ret = dvb_dmx_init(dvbdemux); - if (ret < 0) - goto err_dvb_unregister_adapter; - - dmx = &dvbdemux->dmx; - - dvb->hw_frontend.source = DMX_FRONTEND_0; - dvb->mem_frontend.source = DMX_MEMORY_FE; - dvb->dmxdev.filternum = 256; - dvb->dmxdev.demux = dmx; - - ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter); - if (ret < 0) - goto err_dvb_dmx_release; - - ret = dmx->add_frontend(dmx, &dvb->hw_frontend); - if (ret < 0) - goto err_dvb_dmxdev_release; - - ret = dmx->add_frontend(dmx, &dvb->mem_frontend); - if (ret < 0) - goto err_remove_hw_frontend; - - ret = dmx->connect_frontend(dmx, &dvb->hw_frontend); - if (ret < 0) - goto err_remove_mem_frontend; - - ret = dvb_register(stream); - if (ret < 0) - goto err_disconnect_frontend; - - dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx); - - CX18_INFO("DVB Frontend registered\n"); - CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n", - stream->dvb->dvb_adapter.num, stream->name, - stream->buffers, stream->buf_size/1024, - (stream->buf_size * 100 / 1024) % 100); - - mutex_init(&dvb->feedlock); - dvb->enabled = 1; - return ret; - -err_disconnect_frontend: - dmx->disconnect_frontend(dmx); -err_remove_mem_frontend: - dmx->remove_frontend(dmx, &dvb->mem_frontend); -err_remove_hw_frontend: - dmx->remove_frontend(dmx, &dvb->hw_frontend); -err_dvb_dmxdev_release: - dvb_dmxdev_release(&dvb->dmxdev); -err_dvb_dmx_release: - dvb_dmx_release(dvbdemux); -err_dvb_unregister_adapter: - dvb_unregister_adapter(dvb_adapter); -err_out: - return ret; -} - -void cx18_dvb_unregister(struct cx18_stream *stream) -{ - struct cx18 *cx = stream->cx; - struct cx18_dvb *dvb = stream->dvb; - struct dvb_adapter *dvb_adapter; - struct dvb_demux *dvbdemux; - struct dmx_demux *dmx; - - CX18_INFO("unregister DVB\n"); - - if (dvb == NULL || !dvb->enabled) - return; - - dvb_adapter = &dvb->dvb_adapter; - dvbdemux = &dvb->demux; - dmx = &dvbdemux->dmx; - - dmx->close(dmx); - dvb_net_release(&dvb->dvbnet); - dmx->remove_frontend(dmx, &dvb->mem_frontend); - dmx->remove_frontend(dmx, &dvb->hw_frontend); - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(dvbdemux); - dvb_unregister_frontend(dvb->fe); - dvb_frontend_detach(dvb->fe); - dvb_unregister_adapter(dvb_adapter); -} - -/* All the DVB attach calls go here, this function get's modified - * for each new card. cx18_dvb_start_feed() will also need changes. - */ -static int dvb_register(struct cx18_stream *stream) -{ - struct cx18_dvb *dvb = stream->dvb; - struct cx18 *cx = stream->cx; - int ret = 0; - - switch (cx->card->type) { - case CX18_CARD_HVR_1600_ESMT: - case CX18_CARD_HVR_1600_SAMSUNG: - dvb->fe = dvb_attach(s5h1409_attach, - &hauppauge_hvr1600_config, - &cx->i2c_adap[0]); - if (dvb->fe != NULL) { - dvb_attach(mxl5005s_attach, dvb->fe, - &cx->i2c_adap[0], - &hauppauge_hvr1600_tuner); - ret = 0; - } - break; - case CX18_CARD_HVR_1600_S5H1411: - dvb->fe = dvb_attach(s5h1411_attach, - &hcw_s5h1411_config, - &cx->i2c_adap[0]); - if (dvb->fe != NULL) - dvb_attach(tda18271_attach, dvb->fe, - 0x60, &cx->i2c_adap[0], - &hauppauge_tda18271_config); - break; - case CX18_CARD_LEADTEK_DVR3100H: - dvb->fe = dvb_attach(zl10353_attach, - &leadtek_dvr3100h_demod, - &cx->i2c_adap[1]); - if (dvb->fe != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &cx->i2c_adap[1], - .i2c_addr = 0xc2 >> 1, - .ctrl = NULL, - }; - static struct xc2028_ctrl ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_ZARLINK456, - .type = XC2028_AUTO, - }; - - fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctrl); - } - break; - case CX18_CARD_YUAN_MPC718: - /* - * TODO - * Apparently, these cards also could instead have a - * DiBcom demod supported by one of the db7000 drivers - */ - dvb->fe = dvb_attach(mt352_attach, - &yuan_mpc718_mt352_demod, - &cx->i2c_adap[1]); - if (dvb->fe == NULL) - dvb->fe = dvb_attach(zl10353_attach, - &yuan_mpc718_zl10353_demod, - &cx->i2c_adap[1]); - if (dvb->fe != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &cx->i2c_adap[1], - .i2c_addr = 0xc2 >> 1, - .ctrl = NULL, - }; - static struct xc2028_ctrl ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_ZARLINK456, - .type = XC2028_AUTO, - }; - - fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctrl); - } - break; - case CX18_CARD_GOTVIEW_PCI_DVD3: - dvb->fe = dvb_attach(zl10353_attach, - &gotview_dvd3_zl10353_demod, - &cx->i2c_adap[1]); - if (dvb->fe != NULL) { - struct dvb_frontend *fe; - struct xc2028_config cfg = { - .i2c_adap = &cx->i2c_adap[1], - .i2c_addr = 0xc2 >> 1, - .ctrl = NULL, - }; - static struct xc2028_ctrl ctrl = { - .fname = XC2028_DEFAULT_FIRMWARE, - .max_len = 64, - .demod = XC3028_FE_ZARLINK456, - .type = XC2028_AUTO, - }; - - fe = dvb_attach(xc2028_attach, dvb->fe, &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) - fe->ops.tuner_ops.set_config(fe, &ctrl); - } - break; - default: - /* No Digital Tv Support */ - break; - } - - if (dvb->fe == NULL) { - CX18_ERR("frontend initialization failed\n"); - return -1; - } - - dvb->fe->callback = cx18_reset_tuner_gpio; - - ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe); - if (ret < 0) { - if (dvb->fe->ops.release) - dvb->fe->ops.release(dvb->fe); - return ret; - } - - /* - * The firmware seems to enable the TS DMUX clock - * under various circumstances. However, since we know we - * might use it, let's just turn it on ourselves here. - */ - cx18_write_reg_expect(cx, - (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK, - CX18_CLOCK_ENABLE2, - CX18_DMUX_CLK_MASK, - (CX18_DMUX_CLK_MASK << 16) | CX18_DMUX_CLK_MASK); - - return ret; -} - -MODULE_FIRMWARE(FWFILE); diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h deleted file mode 100644 index bf8d8f6f545..00000000000 --- a/drivers/media/video/cx18/cx18-dvb.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * cx18 functions for DVB support - * - * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include "cx18-driver.h" - -int cx18_dvb_register(struct cx18_stream *stream); -void cx18_dvb_unregister(struct cx18_stream *stream); diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c deleted file mode 100644 index 4bfd865a410..00000000000 --- a/drivers/media/video/cx18/cx18-fileops.c +++ /dev/null @@ -1,881 +0,0 @@ -/* - * cx18 file operation functions - * - * Derived from ivtv-fileops.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-fileops.h" -#include "cx18-i2c.h" -#include "cx18-queue.h" -#include "cx18-vbi.h" -#include "cx18-audio.h" -#include "cx18-mailbox.h" -#include "cx18-scb.h" -#include "cx18-streams.h" -#include "cx18-controls.h" -#include "cx18-ioctl.h" -#include "cx18-cards.h" - -/* This function tries to claim the stream for a specific file descriptor. - If no one else is using this stream then the stream is claimed and - associated VBI and IDX streams are also automatically claimed. - Possible error returns: -EBUSY if someone else has claimed - the stream or 0 on success. */ -int cx18_claim_stream(struct cx18_open_id *id, int type) -{ - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[type]; - struct cx18_stream *s_assoc; - - /* Nothing should ever try to directly claim the IDX stream */ - if (type == CX18_ENC_STREAM_TYPE_IDX) { - CX18_WARN("MPEG Index stream cannot be claimed " - "directly, but something tried.\n"); - return -EINVAL; - } - - if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) { - /* someone already claimed this stream */ - if (s->id == id->open_id) { - /* yes, this file descriptor did. So that's OK. */ - return 0; - } - if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) { - /* VBI is handled already internally, now also assign - the file descriptor to this stream for external - reading of the stream. */ - s->id = id->open_id; - CX18_DEBUG_INFO("Start Read VBI\n"); - return 0; - } - /* someone else is using this stream already */ - CX18_DEBUG_INFO("Stream %d is busy\n", type); - return -EBUSY; - } - s->id = id->open_id; - - /* - * CX18_ENC_STREAM_TYPE_MPG needs to claim: - * CX18_ENC_STREAM_TYPE_VBI, if VBI insertion is on for sliced VBI, or - * CX18_ENC_STREAM_TYPE_IDX, if VBI insertion is off for sliced VBI - * (We don't yet fix up MPEG Index entries for our inserted packets). - * - * For all other streams we're done. - */ - if (type != CX18_ENC_STREAM_TYPE_MPG) - return 0; - - s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - if (cx->vbi.insert_mpeg && !cx18_raw_vbi(cx)) - s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; - else if (!cx18_stream_enabled(s_assoc)) - return 0; - - set_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); - - /* mark that it is used internally */ - set_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags); - return 0; -} -EXPORT_SYMBOL(cx18_claim_stream); - -/* This function releases a previously claimed stream. It will take into - account associated VBI streams. */ -void cx18_release_stream(struct cx18_stream *s) -{ - struct cx18 *cx = s->cx; - struct cx18_stream *s_assoc; - - s->id = -1; - if (s->type == CX18_ENC_STREAM_TYPE_IDX) { - /* - * The IDX stream is only used internally, and can - * only be indirectly unclaimed by unclaiming the MPG stream. - */ - return; - } - - if (s->type == CX18_ENC_STREAM_TYPE_VBI && - test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) { - /* this stream is still in use internally */ - return; - } - if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) { - CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name); - return; - } - - cx18_flush_queues(s); - - /* - * CX18_ENC_STREAM_TYPE_MPG needs to release the - * CX18_ENC_STREAM_TYPE_VBI and/or CX18_ENC_STREAM_TYPE_IDX streams. - * - * For all other streams we're done. - */ - if (s->type != CX18_ENC_STREAM_TYPE_MPG) - return; - - /* Unclaim the associated MPEG Index stream */ - s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { - clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); - cx18_flush_queues(s_assoc); - } - - /* Unclaim the associated VBI stream */ - s_assoc = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; - if (test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_assoc->s_flags)) { - if (s_assoc->id == -1) { - /* - * The VBI stream is not still claimed by a file - * descriptor, so completely unclaim it. - */ - clear_bit(CX18_F_S_CLAIMED, &s_assoc->s_flags); - cx18_flush_queues(s_assoc); - } - } -} -EXPORT_SYMBOL(cx18_release_stream); - -static void cx18_dualwatch(struct cx18 *cx) -{ - struct v4l2_tuner vt; - u32 new_stereo_mode; - const u32 dual = 0x0200; - - new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); - memset(&vt, 0, sizeof(vt)); - cx18_call_all(cx, tuner, g_tuner, &vt); - if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && - (vt.rxsubchans & V4L2_TUNER_SUB_LANG2)) - new_stereo_mode = dual; - - if (new_stereo_mode == cx->dualwatch_stereo_mode) - return; - - CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n", - cx->dualwatch_stereo_mode, new_stereo_mode); - if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode)) - CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n"); -} - - -static struct cx18_mdl *cx18_get_mdl(struct cx18_stream *s, int non_block, - int *err) -{ - struct cx18 *cx = s->cx; - struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; - struct cx18_mdl *mdl; - DEFINE_WAIT(wait); - - *err = 0; - while (1) { - if (s->type == CX18_ENC_STREAM_TYPE_MPG) { - /* Process pending program updates and VBI data */ - if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) { - cx->dualwatch_jiffies = jiffies; - cx18_dualwatch(cx); - } - if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && - !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { - while ((mdl = cx18_dequeue(s_vbi, - &s_vbi->q_full))) { - /* byteswap and process VBI data */ - cx18_process_vbi_data(cx, mdl, - s_vbi->type); - cx18_stream_put_mdl_fw(s_vbi, mdl); - } - } - mdl = &cx->vbi.sliced_mpeg_mdl; - if (mdl->readpos != mdl->bytesused) - return mdl; - } - - /* do we have new data? */ - mdl = cx18_dequeue(s, &s->q_full); - if (mdl) { - if (!test_and_clear_bit(CX18_F_M_NEED_SWAP, - &mdl->m_flags)) - return mdl; - if (s->type == CX18_ENC_STREAM_TYPE_MPG) - /* byteswap MPG data */ - cx18_mdl_swap(mdl); - else { - /* byteswap and process VBI data */ - cx18_process_vbi_data(cx, mdl, s->type); - } - return mdl; - } - - /* return if end of stream */ - if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) { - CX18_DEBUG_INFO("EOS %s\n", s->name); - return NULL; - } - - /* return if file was opened with O_NONBLOCK */ - if (non_block) { - *err = -EAGAIN; - return NULL; - } - - /* wait for more data to arrive */ - prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); - /* New buffers might have become available before we were added - to the waitqueue */ - if (!atomic_read(&s->q_full.depth)) - schedule(); - finish_wait(&s->waitq, &wait); - if (signal_pending(current)) { - /* return if a signal was received */ - CX18_DEBUG_INFO("User stopped %s\n", s->name); - *err = -EINTR; - return NULL; - } - } -} - -static void cx18_setup_sliced_vbi_mdl(struct cx18 *cx) -{ - struct cx18_mdl *mdl = &cx->vbi.sliced_mpeg_mdl; - struct cx18_buffer *buf = &cx->vbi.sliced_mpeg_buf; - int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; - - buf->buf = cx->vbi.sliced_mpeg_data[idx]; - buf->bytesused = cx->vbi.sliced_mpeg_size[idx]; - buf->readpos = 0; - - mdl->curr_buf = NULL; - mdl->bytesused = cx->vbi.sliced_mpeg_size[idx]; - mdl->readpos = 0; -} - -static size_t cx18_copy_buf_to_user(struct cx18_stream *s, - struct cx18_buffer *buf, char __user *ubuf, size_t ucount, bool *stop) -{ - struct cx18 *cx = s->cx; - size_t len = buf->bytesused - buf->readpos; - - *stop = false; - if (len > ucount) - len = ucount; - if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG && - !cx18_raw_vbi(cx) && buf != &cx->vbi.sliced_mpeg_buf) { - /* - * Try to find a good splice point in the PS, just before - * an MPEG-2 Program Pack start code, and provide only - * up to that point to the user, so it's easy to insert VBI data - * the next time around. - * - * This will not work for an MPEG-2 TS and has only been - * verified by analysis to work for an MPEG-2 PS. Helen Buus - * pointed out this works for the CX23416 MPEG-2 DVD compatible - * stream, and research indicates both the MPEG 2 SVCD and DVD - * stream types use an MPEG-2 PS container. - */ - /* - * An MPEG-2 Program Stream (PS) is a series of - * MPEG-2 Program Packs terminated by an - * MPEG Program End Code after the last Program Pack. - * A Program Pack may hold a PS System Header packet and any - * number of Program Elementary Stream (PES) Packets - */ - const char *start = buf->buf + buf->readpos; - const char *p = start + 1; - const u8 *q; - u8 ch = cx->search_pack_header ? 0xba : 0xe0; - int stuffing, i; - - while (start + len > p) { - /* Scan for a 0 to find a potential MPEG-2 start code */ - q = memchr(p, 0, start + len - p); - if (q == NULL) - break; - p = q + 1; - /* - * Keep looking if not a - * MPEG-2 Pack header start code: 0x00 0x00 0x01 0xba - * or MPEG-2 video PES start code: 0x00 0x00 0x01 0xe0 - */ - if ((char *)q + 15 >= buf->buf + buf->bytesused || - q[1] != 0 || q[2] != 1 || q[3] != ch) - continue; - - /* If expecting the primary video PES */ - if (!cx->search_pack_header) { - /* Continue if it couldn't be a PES packet */ - if ((q[6] & 0xc0) != 0x80) - continue; - /* Check if a PTS or PTS & DTS follow */ - if (((q[7] & 0xc0) == 0x80 && /* PTS only */ - (q[9] & 0xf0) == 0x20) || /* PTS only */ - ((q[7] & 0xc0) == 0xc0 && /* PTS & DTS */ - (q[9] & 0xf0) == 0x30)) { /* DTS follows */ - /* Assume we found the video PES hdr */ - ch = 0xba; /* next want a Program Pack*/ - cx->search_pack_header = 1; - p = q + 9; /* Skip this video PES hdr */ - } - continue; - } - - /* We may have found a Program Pack start code */ - - /* Get the count of stuffing bytes & verify them */ - stuffing = q[13] & 7; - /* all stuffing bytes must be 0xff */ - for (i = 0; i < stuffing; i++) - if (q[14 + i] != 0xff) - break; - if (i == stuffing && /* right number of stuffing bytes*/ - (q[4] & 0xc4) == 0x44 && /* marker check */ - (q[12] & 3) == 3 && /* marker check */ - q[14 + stuffing] == 0 && /* PES Pack or Sys Hdr */ - q[15 + stuffing] == 0 && - q[16 + stuffing] == 1) { - /* We declare we actually found a Program Pack*/ - cx->search_pack_header = 0; /* expect vid PES */ - len = (char *)q - start; - cx18_setup_sliced_vbi_mdl(cx); - *stop = true; - break; - } - } - } - if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) { - CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n", - len, s->name); - return -EFAULT; - } - buf->readpos += len; - if (s->type == CX18_ENC_STREAM_TYPE_MPG && - buf != &cx->vbi.sliced_mpeg_buf) - cx->mpg_data_received += len; - return len; -} - -static size_t cx18_copy_mdl_to_user(struct cx18_stream *s, - struct cx18_mdl *mdl, char __user *ubuf, size_t ucount) -{ - size_t tot_written = 0; - int rc; - bool stop = false; - - if (mdl->curr_buf == NULL) - mdl->curr_buf = list_first_entry(&mdl->buf_list, - struct cx18_buffer, list); - - if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { - /* - * For some reason we've exhausted the buffers, but the MDL - * object still said some data was unread. - * Fix that and bail out. - */ - mdl->readpos = mdl->bytesused; - return 0; - } - - list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) { - - if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused) - continue; - - rc = cx18_copy_buf_to_user(s, mdl->curr_buf, ubuf + tot_written, - ucount - tot_written, &stop); - if (rc < 0) - return rc; - mdl->readpos += rc; - tot_written += rc; - - if (stop || /* Forced stopping point for VBI insertion */ - tot_written >= ucount || /* Reader request statisfied */ - mdl->curr_buf->readpos < mdl->curr_buf->bytesused || - mdl->readpos >= mdl->bytesused) /* MDL buffers drained */ - break; - } - return tot_written; -} - -static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf, - size_t tot_count, int non_block) -{ - struct cx18 *cx = s->cx; - size_t tot_written = 0; - int single_frame = 0; - - if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) { - /* shouldn't happen */ - CX18_DEBUG_WARN("Stream %s not initialized before read\n", - s->name); - return -EIO; - } - - /* Each VBI buffer is one frame, the v4l2 API says that for VBI the - frames should arrive one-by-one, so make sure we never output more - than one VBI frame at a time */ - if (s->type == CX18_ENC_STREAM_TYPE_VBI && !cx18_raw_vbi(cx)) - single_frame = 1; - - for (;;) { - struct cx18_mdl *mdl; - int rc; - - mdl = cx18_get_mdl(s, non_block, &rc); - /* if there is no data available... */ - if (mdl == NULL) { - /* if we got data, then return that regardless */ - if (tot_written) - break; - /* EOS condition */ - if (rc == 0) { - clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); - clear_bit(CX18_F_S_APPL_IO, &s->s_flags); - cx18_release_stream(s); - } - /* set errno */ - return rc; - } - - rc = cx18_copy_mdl_to_user(s, mdl, ubuf + tot_written, - tot_count - tot_written); - - if (mdl != &cx->vbi.sliced_mpeg_mdl) { - if (mdl->readpos == mdl->bytesused) - cx18_stream_put_mdl_fw(s, mdl); - else - cx18_push(s, mdl, &s->q_full); - } else if (mdl->readpos == mdl->bytesused) { - int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES; - - cx->vbi.sliced_mpeg_size[idx] = 0; - cx->vbi.inserted_frame++; - cx->vbi_data_inserted += mdl->bytesused; - } - if (rc < 0) - return rc; - tot_written += rc; - - if (tot_written == tot_count || single_frame) - break; - } - return tot_written; -} - -static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf, - size_t count, loff_t *pos, int non_block) -{ - ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0; - struct cx18 *cx = s->cx; - - CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); - if (rc > 0) - pos += rc; - return rc; -} - -int cx18_start_capture(struct cx18_open_id *id) -{ - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - struct cx18_stream *s_vbi; - struct cx18_stream *s_idx; - - if (s->type == CX18_ENC_STREAM_TYPE_RAD) { - /* you cannot read from these stream types. */ - return -EPERM; - } - - /* Try to claim this stream. */ - if (cx18_claim_stream(id, s->type)) - return -EBUSY; - - /* If capture is already in progress, then we also have to - do nothing extra. */ - if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || - test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { - set_bit(CX18_F_S_APPL_IO, &s->s_flags); - return 0; - } - - /* Start associated VBI or IDX stream capture if required */ - s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; - s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - if (s->type == CX18_ENC_STREAM_TYPE_MPG) { - /* - * The VBI and IDX streams should have been claimed - * automatically, if for internal use, when the MPG stream was - * claimed. We only need to start these streams capturing. - */ - if (test_bit(CX18_F_S_INTERNAL_USE, &s_idx->s_flags) && - !test_and_set_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { - if (cx18_start_v4l2_encode_stream(s_idx)) { - CX18_DEBUG_WARN("IDX capture start failed\n"); - clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); - goto start_failed; - } - CX18_DEBUG_INFO("IDX capture started\n"); - } - if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) && - !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) { - if (cx18_start_v4l2_encode_stream(s_vbi)) { - CX18_DEBUG_WARN("VBI capture start failed\n"); - clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); - goto start_failed; - } - CX18_DEBUG_INFO("VBI insertion started\n"); - } - } - - /* Tell the card to start capturing */ - if (!cx18_start_v4l2_encode_stream(s)) { - /* We're done */ - set_bit(CX18_F_S_APPL_IO, &s->s_flags); - /* Resume a possibly paused encoder */ - if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) - cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle); - return 0; - } - -start_failed: - CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name); - - /* - * The associated VBI and IDX streams for internal use are released - * automatically when the MPG stream is released. We only need to stop - * the associated stream. - */ - if (s->type == CX18_ENC_STREAM_TYPE_MPG) { - /* Stop the IDX stream which is always for internal use */ - if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { - cx18_stop_v4l2_encode_stream(s_idx, 0); - clear_bit(CX18_F_S_STREAMING, &s_idx->s_flags); - } - /* Stop the VBI stream, if only running for internal use */ - if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && - !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { - cx18_stop_v4l2_encode_stream(s_vbi, 0); - clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags); - } - } - clear_bit(CX18_F_S_STREAMING, &s->s_flags); - cx18_release_stream(s); /* Also releases associated streams */ - return -EIO; -} - -ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, - loff_t *pos) -{ - struct cx18_open_id *id = file2id(filp); - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - int rc; - - CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name); - - mutex_lock(&cx->serialize_lock); - rc = cx18_start_capture(id); - mutex_unlock(&cx->serialize_lock); - if (rc) - return rc; - - if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (id->type == CX18_ENC_STREAM_TYPE_YUV)) { - return videobuf_read_stream(&s->vbuf_q, buf, count, pos, 0, - filp->f_flags & O_NONBLOCK); - } - - return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK); -} - -unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) -{ - struct cx18_open_id *id = file2id(filp); - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); - - /* Start a capture if there is none */ - if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { - int rc; - - mutex_lock(&cx->serialize_lock); - rc = cx18_start_capture(id); - mutex_unlock(&cx->serialize_lock); - if (rc) { - CX18_DEBUG_INFO("Could not start capture for %s (%d)\n", - s->name, rc); - return POLLERR; - } - CX18_DEBUG_FILE("Encoder poll started capture\n"); - } - - if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (id->type == CX18_ENC_STREAM_TYPE_YUV)) { - int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait); - if (eof && videobuf_poll == POLLERR) - return POLLHUP; - else - return videobuf_poll; - } - - /* add stream's waitq to the poll list */ - CX18_DEBUG_HI_FILE("Encoder poll\n"); - poll_wait(filp, &s->waitq, wait); - - if (atomic_read(&s->q_full.depth)) - return POLLIN | POLLRDNORM; - if (eof) - return POLLHUP; - return 0; -} - -int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); - - if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (id->type == CX18_ENC_STREAM_TYPE_YUV)) { - - /* Start a capture if there is none */ - if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { - int rc; - - mutex_lock(&cx->serialize_lock); - rc = cx18_start_capture(id); - mutex_unlock(&cx->serialize_lock); - if (rc) { - CX18_DEBUG_INFO( - "Could not start capture for %s (%d)\n", - s->name, rc); - return -EINVAL; - } - CX18_DEBUG_FILE("Encoder mmap started capture\n"); - } - - return videobuf_mmap_mapper(&s->vbuf_q, vma); - } - - return -EINVAL; -} - -void cx18_vb_timeout(unsigned long data) -{ - struct cx18_stream *s = (struct cx18_stream *)data; - struct cx18_videobuf_buffer *buf; - unsigned long flags; - - /* Return all of the buffers in error state, so the vbi/vid inode - * can return from blocking. - */ - spin_lock_irqsave(&s->vb_lock, flags); - while (!list_empty(&s->vb_capture)) { - buf = list_entry(s->vb_capture.next, - struct cx18_videobuf_buffer, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - } - spin_unlock_irqrestore(&s->vb_lock, flags); -} - -void cx18_stop_capture(struct cx18_open_id *id, int gop_end) -{ - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI]; - struct cx18_stream *s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - - CX18_DEBUG_IOCTL("close() of %s\n", s->name); - - /* 'Unclaim' this stream */ - - /* Stop capturing */ - if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) { - CX18_DEBUG_INFO("close stopping capture\n"); - if (id->type == CX18_ENC_STREAM_TYPE_MPG) { - /* Stop internal use associated VBI and IDX streams */ - if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && - !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { - CX18_DEBUG_INFO("close stopping embedded VBI " - "capture\n"); - cx18_stop_v4l2_encode_stream(s_vbi, 0); - } - if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { - CX18_DEBUG_INFO("close stopping IDX capture\n"); - cx18_stop_v4l2_encode_stream(s_idx, 0); - } - } - if (id->type == CX18_ENC_STREAM_TYPE_VBI && - test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) - /* Also used internally, don't stop capturing */ - s->id = -1; - else - cx18_stop_v4l2_encode_stream(s, gop_end); - } - if (!gop_end) { - clear_bit(CX18_F_S_APPL_IO, &s->s_flags); - clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); - cx18_release_stream(s); - } -} - -int cx18_v4l2_close(struct file *filp) -{ - struct v4l2_fh *fh = filp->private_data; - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - CX18_DEBUG_IOCTL("close() of %s\n", s->name); - - mutex_lock(&cx->serialize_lock); - /* Stop radio */ - if (id->type == CX18_ENC_STREAM_TYPE_RAD && - v4l2_fh_is_singular_file(filp)) { - /* Closing radio device, return to TV mode */ - cx18_mute(cx); - /* Mark that the radio is no longer in use */ - clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags); - /* Switch tuner to TV */ - cx18_call_all(cx, core, s_std, cx->std); - /* Select correct audio input (i.e. TV tuner or Line in) */ - cx18_audio_set_io(cx); - if (atomic_read(&cx->ana_capturing) > 0) { - /* Undo video mute */ - cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, - (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) | - (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8))); - } - /* Done! Unmute and continue. */ - cx18_unmute(cx); - } - - v4l2_fh_del(fh); - v4l2_fh_exit(fh); - - /* 'Unclaim' this stream */ - if (s->id == id->open_id) - cx18_stop_capture(id, 0); - kfree(id); - mutex_unlock(&cx->serialize_lock); - return 0; -} - -static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) -{ - struct cx18 *cx = s->cx; - struct cx18_open_id *item; - - CX18_DEBUG_FILE("open %s\n", s->name); - - /* Allocate memory */ - item = kzalloc(sizeof(struct cx18_open_id), GFP_KERNEL); - if (NULL == item) { - CX18_DEBUG_WARN("nomem on v4l2 open\n"); - return -ENOMEM; - } - v4l2_fh_init(&item->fh, s->video_dev); - - item->cx = cx; - item->type = s->type; - - item->open_id = cx->open_id++; - filp->private_data = &item->fh; - v4l2_fh_add(&item->fh); - - if (item->type == CX18_ENC_STREAM_TYPE_RAD && - v4l2_fh_is_singular_file(filp)) { - if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) { - if (atomic_read(&cx->ana_capturing) > 0) { - /* switching to radio while capture is - in progress is not polite */ - v4l2_fh_del(&item->fh); - v4l2_fh_exit(&item->fh); - kfree(item); - return -EBUSY; - } - } - - /* Mark that the radio is being used. */ - set_bit(CX18_F_I_RADIO_USER, &cx->i_flags); - /* We have the radio */ - cx18_mute(cx); - /* Switch tuner to radio */ - cx18_call_all(cx, tuner, s_radio); - /* Select the correct audio input (i.e. radio tuner) */ - cx18_audio_set_io(cx); - /* Done! Unmute and continue. */ - cx18_unmute(cx); - } - return 0; -} - -int cx18_v4l2_open(struct file *filp) -{ - int res; - struct video_device *video_dev = video_devdata(filp); - struct cx18_stream *s = video_get_drvdata(video_dev); - struct cx18 *cx = s->cx; - - mutex_lock(&cx->serialize_lock); - if (cx18_init_on_first_open(cx)) { - CX18_ERR("Failed to initialize on %s\n", - video_device_node_name(video_dev)); - mutex_unlock(&cx->serialize_lock); - return -ENXIO; - } - res = cx18_serialized_open(s, filp); - mutex_unlock(&cx->serialize_lock); - return res; -} - -void cx18_mute(struct cx18 *cx) -{ - u32 h; - if (atomic_read(&cx->ana_capturing)) { - h = cx18_find_handle(cx); - if (h != CX18_INVALID_TASK_HANDLE) - cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 1); - else - CX18_ERR("Can't find valid task handle for mute\n"); - } - CX18_DEBUG_INFO("Mute\n"); -} - -void cx18_unmute(struct cx18 *cx) -{ - u32 h; - if (atomic_read(&cx->ana_capturing)) { - h = cx18_find_handle(cx); - if (h != CX18_INVALID_TASK_HANDLE) { - cx18_msleep_timeout(100, 0); - cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, h, 12); - cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, h, 0); - } else - CX18_ERR("Can't find valid task handle for unmute\n"); - } - CX18_DEBUG_INFO("Unmute\n"); -} diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h deleted file mode 100644 index b9e5110ad04..00000000000 --- a/drivers/media/video/cx18/cx18-fileops.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * cx18 file operation functions - * - * Derived from ivtv-fileops.h - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -/* Testing/Debugging */ -int cx18_v4l2_open(struct file *filp); -ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, - loff_t *pos); -ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count, - loff_t *pos); -int cx18_v4l2_close(struct file *filp); -unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait); -int cx18_start_capture(struct cx18_open_id *id); -void cx18_stop_capture(struct cx18_open_id *id, int gop_end); -void cx18_mute(struct cx18 *cx); -void cx18_unmute(struct cx18 *cx); -int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma); -void cx18_vb_timeout(unsigned long data); - -/* Shared with cx18-alsa module */ -int cx18_claim_stream(struct cx18_open_id *id, int type); -void cx18_release_stream(struct cx18_stream *s); diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c deleted file mode 100644 index a1c1cec05f9..00000000000 --- a/drivers/media/video/cx18/cx18-firmware.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * cx18 firmware functions - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-scb.h" -#include "cx18-irq.h" -#include "cx18-firmware.h" -#include "cx18-cards.h" -#include <linux/firmware.h> - -#define CX18_PROC_SOFT_RESET 0xc70010 -#define CX18_DDR_SOFT_RESET 0xc70014 -#define CX18_CLOCK_SELECT1 0xc71000 -#define CX18_CLOCK_SELECT2 0xc71004 -#define CX18_HALF_CLOCK_SELECT1 0xc71008 -#define CX18_HALF_CLOCK_SELECT2 0xc7100C -#define CX18_CLOCK_POLARITY1 0xc71010 -#define CX18_CLOCK_POLARITY2 0xc71014 -#define CX18_ADD_DELAY_ENABLE1 0xc71018 -#define CX18_ADD_DELAY_ENABLE2 0xc7101C -#define CX18_CLOCK_ENABLE1 0xc71020 -#define CX18_CLOCK_ENABLE2 0xc71024 - -#define CX18_REG_BUS_TIMEOUT_EN 0xc72024 - -#define CX18_FAST_CLOCK_PLL_INT 0xc78000 -#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004 -#define CX18_FAST_CLOCK_PLL_POST 0xc78008 -#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C -#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010 - -#define CX18_SLOW_CLOCK_PLL_INT 0xc78014 -#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018 -#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C -#define CX18_MPEG_CLOCK_PLL_INT 0xc78040 -#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044 -#define CX18_MPEG_CLOCK_PLL_POST 0xc78048 -#define CX18_PLL_POWER_DOWN 0xc78088 -#define CX18_SW1_INT_STATUS 0xc73104 -#define CX18_SW1_INT_ENABLE_PCI 0xc7311C -#define CX18_SW2_INT_SET 0xc73140 -#define CX18_SW2_INT_STATUS 0xc73144 -#define CX18_ADEC_CONTROL 0xc78120 - -#define CX18_DDR_REQUEST_ENABLE 0xc80000 -#define CX18_DDR_CHIP_CONFIG 0xc80004 -#define CX18_DDR_REFRESH 0xc80008 -#define CX18_DDR_TIMING1 0xc8000C -#define CX18_DDR_TIMING2 0xc80010 -#define CX18_DDR_POWER_REG 0xc8001C - -#define CX18_DDR_TUNE_LANE 0xc80048 -#define CX18_DDR_INITIAL_EMRS 0xc80054 -#define CX18_DDR_MB_PER_ROW_7 0xc8009C -#define CX18_DDR_BASE_63_ADDR 0xc804FC - -#define CX18_WMB_CLIENT02 0xc90108 -#define CX18_WMB_CLIENT05 0xc90114 -#define CX18_WMB_CLIENT06 0xc90118 -#define CX18_WMB_CLIENT07 0xc9011C -#define CX18_WMB_CLIENT08 0xc90120 -#define CX18_WMB_CLIENT09 0xc90124 -#define CX18_WMB_CLIENT10 0xc90128 -#define CX18_WMB_CLIENT11 0xc9012C -#define CX18_WMB_CLIENT12 0xc90130 -#define CX18_WMB_CLIENT13 0xc90134 -#define CX18_WMB_CLIENT14 0xc90138 - -#define CX18_DSP0_INTERRUPT_MASK 0xd0004C - -#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */ -#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */ - -struct cx18_apu_rom_seghdr { - u32 sync1; - u32 sync2; - u32 addr; - u32 size; -}; - -static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx) -{ - const struct firmware *fw = NULL; - int i, j; - unsigned size; - u32 __iomem *dst = (u32 __iomem *)mem; - const u32 *src; - - if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { - CX18_ERR("Unable to open firmware %s\n", fn); - CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n"); - return -ENOMEM; - } - - src = (const u32 *)fw->data; - - for (i = 0; i < fw->size; i += 4096) { - cx18_setup_page(cx, i); - for (j = i; j < fw->size && j < i + 4096; j += 4) { - /* no need for endianness conversion on the ppc */ - cx18_raw_writel(cx, *src, dst); - if (cx18_raw_readl(cx, dst) != *src) { - CX18_ERR("Mismatch at offset %x\n", i); - release_firmware(fw); - cx18_setup_page(cx, 0); - return -EIO; - } - dst++; - src++; - } - } - if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) - CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size); - size = fw->size; - release_firmware(fw); - cx18_setup_page(cx, SCB_OFFSET); - return size; -} - -static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, - u32 *entry_addr) -{ - const struct firmware *fw = NULL; - int i, j; - unsigned size; - const u32 *src; - struct cx18_apu_rom_seghdr seghdr; - const u8 *vers; - u32 offset = 0; - u32 apu_version = 0; - int sz; - - if (request_firmware(&fw, fn, &cx->pci_dev->dev)) { - CX18_ERR("unable to open firmware %s\n", fn); - CX18_ERR("did you put the firmware in the hotplug firmware directory?\n"); - cx18_setup_page(cx, 0); - return -ENOMEM; - } - - *entry_addr = 0; - src = (const u32 *)fw->data; - vers = fw->data + sizeof(seghdr); - sz = fw->size; - - apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32]; - while (offset + sizeof(seghdr) < fw->size) { - const u32 *shptr = src + offset / 4; - - seghdr.sync1 = le32_to_cpu(shptr[0]); - seghdr.sync2 = le32_to_cpu(shptr[1]); - seghdr.addr = le32_to_cpu(shptr[2]); - seghdr.size = le32_to_cpu(shptr[3]); - - offset += sizeof(seghdr); - if (seghdr.sync1 != APU_ROM_SYNC1 || - seghdr.sync2 != APU_ROM_SYNC2) { - offset += seghdr.size; - continue; - } - CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr, - seghdr.addr + seghdr.size - 1); - if (*entry_addr == 0) - *entry_addr = seghdr.addr; - if (offset + seghdr.size > sz) - break; - for (i = 0; i < seghdr.size; i += 4096) { - cx18_setup_page(cx, seghdr.addr + i); - for (j = i; j < seghdr.size && j < i + 4096; j += 4) { - /* no need for endianness conversion on the ppc */ - cx18_raw_writel(cx, src[(offset + j) / 4], - dst + seghdr.addr + j); - if (cx18_raw_readl(cx, dst + seghdr.addr + j) - != src[(offset + j) / 4]) { - CX18_ERR("Mismatch at offset %x\n", - offset + j); - release_firmware(fw); - cx18_setup_page(cx, 0); - return -EIO; - } - } - } - offset += seghdr.size; - } - if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags)) - CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n", - fn, apu_version, fw->size); - size = fw->size; - release_firmware(fw); - cx18_setup_page(cx, 0); - return size; -} - -void cx18_halt_firmware(struct cx18 *cx) -{ - CX18_DEBUG_INFO("Preparing for firmware halt.\n"); - cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, - 0x0000000F, 0x000F000F); - cx18_write_reg_expect(cx, 0x00020002, CX18_ADEC_CONTROL, - 0x00000002, 0x00020002); -} - -void cx18_init_power(struct cx18 *cx, int lowpwr) -{ - /* power-down Spare and AOM PLLs */ - /* power-up fast, slow and mpeg PLLs */ - cx18_write_reg(cx, 0x00000008, CX18_PLL_POWER_DOWN); - - /* ADEC out of sleep */ - cx18_write_reg_expect(cx, 0x00020000, CX18_ADEC_CONTROL, - 0x00000000, 0x00020002); - - /* - * The PLL parameters are based on the external crystal frequency that - * would ideally be: - * - * NTSC Color subcarrier freq * 8 = - * 4.5 MHz/286 * 455/2 * 8 = 28.63636363... MHz - * - * The accidents of history and rationale that explain from where this - * combination of magic numbers originate can be found in: - * - * [1] Abrahams, I. C., "Choice of Chrominance Subcarrier Frequency in - * the NTSC Standards", Proceedings of the I-R-E, January 1954, pp 79-80 - * - * [2] Abrahams, I. C., "The 'Frequency Interleaving' Principle in the - * NTSC Standards", Proceedings of the I-R-E, January 1954, pp 81-83 - * - * As Mike Bradley has rightly pointed out, it's not the exact crystal - * frequency that matters, only that all parts of the driver and - * firmware are using the same value (close to the ideal value). - * - * Since I have a strong suspicion that, if the firmware ever assumes a - * crystal value at all, it will assume 28.636360 MHz, the crystal - * freq used in calculations in this driver will be: - * - * xtal_freq = 28.636360 MHz - * - * an error of less than 0.13 ppm which is way, way better than any off - * the shelf crystal will have for accuracy anyway. - * - * Below I aim to run the PLLs' VCOs near 400 MHz to minimze errors. - * - * Many thanks to Jeff Campbell and Mike Bradley for their extensive - * investigation, experimentation, testing, and suggested solutions of - * of audio/video sync problems with SVideo and CVBS captures. - */ - - /* the fast clock is at 200/245 MHz */ - /* 1 * xtal_freq * 0x0d.f7df9b8 / 2 = 200 MHz: 400 MHz pre post-divide*/ - /* 1 * xtal_freq * 0x11.1c71eb8 / 2 = 245 MHz: 490 MHz pre post-divide*/ - cx18_write_reg(cx, lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT); - cx18_write_reg(cx, lowpwr ? 0x1EFBF37 : 0x038E3D7, - CX18_FAST_CLOCK_PLL_FRAC); - - cx18_write_reg(cx, 2, CX18_FAST_CLOCK_PLL_POST); - cx18_write_reg(cx, 1, CX18_FAST_CLOCK_PLL_PRESCALE); - cx18_write_reg(cx, 4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH); - - /* set slow clock to 125/120 MHz */ - /* xtal_freq * 0x0d.1861a20 / 3 = 125 MHz: 375 MHz before post-divide */ - /* xtal_freq * 0x0c.92493f8 / 3 = 120 MHz: 360 MHz before post-divide */ - cx18_write_reg(cx, lowpwr ? 0xD : 0xC, CX18_SLOW_CLOCK_PLL_INT); - cx18_write_reg(cx, lowpwr ? 0x30C344 : 0x124927F, - CX18_SLOW_CLOCK_PLL_FRAC); - cx18_write_reg(cx, 3, CX18_SLOW_CLOCK_PLL_POST); - - /* mpeg clock pll 54MHz */ - /* xtal_freq * 0xf.15f17f0 / 8 = 54 MHz: 432 MHz before post-divide */ - cx18_write_reg(cx, 0xF, CX18_MPEG_CLOCK_PLL_INT); - cx18_write_reg(cx, 0x2BE2FE, CX18_MPEG_CLOCK_PLL_FRAC); - cx18_write_reg(cx, 8, CX18_MPEG_CLOCK_PLL_POST); - - /* Defaults */ - /* APU = SC or SC/2 = 125/62.5 */ - /* EPU = SC = 125 */ - /* DDR = FC = 180 */ - /* ENC = SC = 125 */ - /* AI1 = SC = 125 */ - /* VIM2 = disabled */ - /* PCI = FC/2 = 90 */ - /* AI2 = disabled */ - /* DEMUX = disabled */ - /* AO = SC/2 = 62.5 */ - /* SER = 54MHz */ - /* VFC = disabled */ - /* USB = disabled */ - - if (lowpwr) { - cx18_write_reg_expect(cx, 0xFFFF0020, CX18_CLOCK_SELECT1, - 0x00000020, 0xFFFFFFFF); - cx18_write_reg_expect(cx, 0xFFFF0004, CX18_CLOCK_SELECT2, - 0x00000004, 0xFFFFFFFF); - } else { - /* This doesn't explicitly set every clock select */ - cx18_write_reg_expect(cx, 0x00060004, CX18_CLOCK_SELECT1, - 0x00000004, 0x00060006); - cx18_write_reg_expect(cx, 0x00060006, CX18_CLOCK_SELECT2, - 0x00000006, 0x00060006); - } - - cx18_write_reg_expect(cx, 0xFFFF0002, CX18_HALF_CLOCK_SELECT1, - 0x00000002, 0xFFFFFFFF); - cx18_write_reg_expect(cx, 0xFFFF0104, CX18_HALF_CLOCK_SELECT2, - 0x00000104, 0xFFFFFFFF); - cx18_write_reg_expect(cx, 0xFFFF9026, CX18_CLOCK_ENABLE1, - 0x00009026, 0xFFFFFFFF); - cx18_write_reg_expect(cx, 0xFFFF3105, CX18_CLOCK_ENABLE2, - 0x00003105, 0xFFFFFFFF); -} - -void cx18_init_memory(struct cx18 *cx) -{ - cx18_msleep_timeout(10, 0); - cx18_write_reg_expect(cx, 0x00010000, CX18_DDR_SOFT_RESET, - 0x00000000, 0x00010001); - cx18_msleep_timeout(10, 0); - - cx18_write_reg(cx, cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG); - - cx18_msleep_timeout(10, 0); - - cx18_write_reg(cx, cx->card->ddr.refresh, CX18_DDR_REFRESH); - cx18_write_reg(cx, cx->card->ddr.timing1, CX18_DDR_TIMING1); - cx18_write_reg(cx, cx->card->ddr.timing2, CX18_DDR_TIMING2); - - cx18_msleep_timeout(10, 0); - - /* Initialize DQS pad time */ - cx18_write_reg(cx, cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE); - cx18_write_reg(cx, cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS); - - cx18_msleep_timeout(10, 0); - - cx18_write_reg_expect(cx, 0x00020000, CX18_DDR_SOFT_RESET, - 0x00000000, 0x00020002); - cx18_msleep_timeout(10, 0); - - /* use power-down mode when idle */ - cx18_write_reg(cx, 0x00000010, CX18_DDR_POWER_REG); - - cx18_write_reg_expect(cx, 0x00010001, CX18_REG_BUS_TIMEOUT_EN, - 0x00000001, 0x00010001); - - cx18_write_reg(cx, 0x48, CX18_DDR_MB_PER_ROW_7); - cx18_write_reg(cx, 0xE0000, CX18_DDR_BASE_63_ADDR); - - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT02); /* AO */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT09); /* AI2 */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT05); /* VIM1 */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT06); /* AI1 */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT07); /* 3D comb */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT10); /* ME */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT12); /* ENC */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT13); /* PK */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT11); /* RC */ - cx18_write_reg(cx, 0x00000101, CX18_WMB_CLIENT14); /* AVO */ -} - -#define CX18_CPU_FIRMWARE "v4l-cx23418-cpu.fw" -#define CX18_APU_FIRMWARE "v4l-cx23418-apu.fw" - -int cx18_firmware_init(struct cx18 *cx) -{ - u32 fw_entry_addr; - int sz, retries; - u32 api_args[MAX_MB_ARGUMENTS]; - - /* Allow chip to control CLKRUN */ - cx18_write_reg(cx, 0x5, CX18_DSP0_INTERRUPT_MASK); - - /* Stop the firmware */ - cx18_write_reg_expect(cx, 0x000F000F, CX18_PROC_SOFT_RESET, - 0x0000000F, 0x000F000F); - - cx18_msleep_timeout(1, 0); - - /* If the CPU is still running */ - if ((cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 8) == 0) { - CX18_ERR("%s: couldn't stop CPU to load firmware\n", __func__); - return -EIO; - } - - cx18_sw1_irq_enable(cx, IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU); - cx18_sw2_irq_enable(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); - - sz = load_cpu_fw_direct(CX18_CPU_FIRMWARE, cx->enc_mem, cx); - if (sz <= 0) - return sz; - - /* The SCB & IPC area *must* be correct before starting the firmwares */ - cx18_init_scb(cx); - - fw_entry_addr = 0; - sz = load_apu_fw_direct(CX18_APU_FIRMWARE, cx->enc_mem, cx, - &fw_entry_addr); - if (sz <= 0) - return sz; - - /* Start the CPU. The CPU will take care of the APU for us. */ - cx18_write_reg_expect(cx, 0x00080000, CX18_PROC_SOFT_RESET, - 0x00000000, 0x00080008); - - /* Wait up to 500 ms for the APU to come out of reset */ - for (retries = 0; - retries < 50 && (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1; - retries++) - cx18_msleep_timeout(10, 0); - - cx18_msleep_timeout(200, 0); - - if (retries == 50 && - (cx18_read_reg(cx, CX18_PROC_SOFT_RESET) & 1) == 1) { - CX18_ERR("Could not start the CPU\n"); - return -EIO; - } - - /* - * The CPU had once before set up to receive an interrupt for it's - * outgoing IRQ_CPU_TO_EPU_ACK to us. If it ever does this, we get an - * interrupt when it sends us an ack, but by the time we process it, - * that flag in the SW2 status register has been cleared by the CPU - * firmware. We'll prevent that not so useful condition from happening - * by clearing the CPU's interrupt enables for Ack IRQ's we want to - * process. - */ - cx18_sw2_irq_disable_cpu(cx, IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK); - - /* Try a benign command to see if the CPU is alive and well */ - sz = cx18_vapi_result(cx, api_args, CX18_CPU_DEBUG_PEEK32, 1, 0); - if (sz < 0) - return sz; - - /* initialize GPIO */ - cx18_write_reg_expect(cx, 0x14001400, 0xc78110, 0x00001400, 0x14001400); - return 0; -} - -MODULE_FIRMWARE(CX18_CPU_FIRMWARE); -MODULE_FIRMWARE(CX18_APU_FIRMWARE); diff --git a/drivers/media/video/cx18/cx18-firmware.h b/drivers/media/video/cx18/cx18-firmware.h deleted file mode 100644 index 38d4c05e849..00000000000 --- a/drivers/media/video/cx18/cx18-firmware.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * cx18 firmware functions - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -int cx18_firmware_init(struct cx18 *cx); -void cx18_halt_firmware(struct cx18 *cx); -void cx18_init_memory(struct cx18 *cx); -void cx18_init_power(struct cx18 *cx, int lowpwr); diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c deleted file mode 100644 index 5374aeb0cd2..00000000000 --- a/drivers/media/video/cx18/cx18-gpio.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * cx18 gpio functions - * - * Derived from ivtv-gpio.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-cards.h" -#include "cx18-gpio.h" -#include "tuner-xc2028.h" - -/********************* GPIO stuffs *********************/ - -/* GPIO registers */ -#define CX18_REG_GPIO_IN 0xc72010 -#define CX18_REG_GPIO_OUT1 0xc78100 -#define CX18_REG_GPIO_DIR1 0xc78108 -#define CX18_REG_GPIO_OUT2 0xc78104 -#define CX18_REG_GPIO_DIR2 0xc7810c - -/* - * HVR-1600 GPIO pins, courtesy of Hauppauge: - * - * gpio0: zilog ir process reset pin - * gpio1: zilog programming pin (you should never use this) - * gpio12: cx24227 reset pin - * gpio13: cs5345 reset pin -*/ - -/* - * File scope utility functions - */ -static void gpio_write(struct cx18 *cx) -{ - u32 dir_lo = cx->gpio_dir & 0xffff; - u32 val_lo = cx->gpio_val & 0xffff; - u32 dir_hi = cx->gpio_dir >> 16; - u32 val_hi = cx->gpio_val >> 16; - - cx18_write_reg_expect(cx, dir_lo << 16, - CX18_REG_GPIO_DIR1, ~dir_lo, dir_lo); - cx18_write_reg_expect(cx, (dir_lo << 16) | val_lo, - CX18_REG_GPIO_OUT1, val_lo, dir_lo); - cx18_write_reg_expect(cx, dir_hi << 16, - CX18_REG_GPIO_DIR2, ~dir_hi, dir_hi); - cx18_write_reg_expect(cx, (dir_hi << 16) | val_hi, - CX18_REG_GPIO_OUT2, val_hi, dir_hi); -} - -static void gpio_update(struct cx18 *cx, u32 mask, u32 data) -{ - if (mask == 0) - return; - - mutex_lock(&cx->gpio_lock); - cx->gpio_val = (cx->gpio_val & ~mask) | (data & mask); - gpio_write(cx); - mutex_unlock(&cx->gpio_lock); -} - -static void gpio_reset_seq(struct cx18 *cx, u32 active_lo, u32 active_hi, - unsigned int assert_msecs, - unsigned int recovery_msecs) -{ - u32 mask; - - mask = active_lo | active_hi; - if (mask == 0) - return; - - /* - * Assuming that active_hi and active_lo are a subsets of the bits in - * gpio_dir. Also assumes that active_lo and active_hi don't overlap - * in any bit position - */ - - /* Assert */ - gpio_update(cx, mask, ~active_lo); - schedule_timeout_uninterruptible(msecs_to_jiffies(assert_msecs)); - - /* Deassert */ - gpio_update(cx, mask, ~active_hi); - schedule_timeout_uninterruptible(msecs_to_jiffies(recovery_msecs)); -} - -/* - * GPIO Multiplexer - logical device - */ -static int gpiomux_log_status(struct v4l2_subdev *sd) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - mutex_lock(&cx->gpio_lock); - CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n", - cx->gpio_dir, cx->gpio_val); - mutex_unlock(&cx->gpio_lock); - return 0; -} - -static int gpiomux_s_radio(struct v4l2_subdev *sd) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - /* - * FIXME - work out the cx->active/audio_input mess - this is - * intended to handle the switch to radio mode and set the - * audio routing, but we need to update the state in cx - */ - gpio_update(cx, cx->card->gpio_audio_input.mask, - cx->card->gpio_audio_input.radio); - return 0; -} - -static int gpiomux_s_std(struct v4l2_subdev *sd, v4l2_std_id norm) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - u32 data; - - switch (cx->card->audio_inputs[cx->audio_input].muxer_input) { - case 1: - data = cx->card->gpio_audio_input.linein; - break; - case 0: - data = cx->card->gpio_audio_input.tuner; - break; - default: - /* - * FIXME - work out the cx->active/audio_input mess - this is - * intended to handle the switch from radio mode and set the - * audio routing, but we need to update the state in cx - */ - data = cx->card->gpio_audio_input.tuner; - break; - } - gpio_update(cx, cx->card->gpio_audio_input.mask, data); - return 0; -} - -static int gpiomux_s_audio_routing(struct v4l2_subdev *sd, - u32 input, u32 output, u32 config) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - u32 data; - - switch (input) { - case 0: - data = cx->card->gpio_audio_input.tuner; - break; - case 1: - data = cx->card->gpio_audio_input.linein; - break; - case 2: - data = cx->card->gpio_audio_input.radio; - break; - default: - return -EINVAL; - } - gpio_update(cx, cx->card->gpio_audio_input.mask, data); - return 0; -} - -static const struct v4l2_subdev_core_ops gpiomux_core_ops = { - .log_status = gpiomux_log_status, - .s_std = gpiomux_s_std, -}; - -static const struct v4l2_subdev_tuner_ops gpiomux_tuner_ops = { - .s_radio = gpiomux_s_radio, -}; - -static const struct v4l2_subdev_audio_ops gpiomux_audio_ops = { - .s_routing = gpiomux_s_audio_routing, -}; - -static const struct v4l2_subdev_ops gpiomux_ops = { - .core = &gpiomux_core_ops, - .tuner = &gpiomux_tuner_ops, - .audio = &gpiomux_audio_ops, -}; - -/* - * GPIO Reset Controller - logical device - */ -static int resetctrl_log_status(struct v4l2_subdev *sd) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - - mutex_lock(&cx->gpio_lock); - CX18_INFO_DEV(sd, "GPIO: direction 0x%08x, value 0x%08x\n", - cx->gpio_dir, cx->gpio_val); - mutex_unlock(&cx->gpio_lock); - return 0; -} - -static int resetctrl_reset(struct v4l2_subdev *sd, u32 val) -{ - struct cx18 *cx = v4l2_get_subdevdata(sd); - const struct cx18_gpio_i2c_slave_reset *p; - - p = &cx->card->gpio_i2c_slave_reset; - switch (val) { - case CX18_GPIO_RESET_I2C: - gpio_reset_seq(cx, p->active_lo_mask, p->active_hi_mask, - p->msecs_asserted, p->msecs_recovery); - break; - case CX18_GPIO_RESET_Z8F0811: - /* - * Assert timing for the Z8F0811 on HVR-1600 boards: - * 1. Assert RESET for min of 4 clock cycles at 18.432 MHz to - * initiate - * 2. Reset then takes 66 WDT cycles at 10 kHz + 16 xtal clock - * cycles (6,601,085 nanoseconds ~= 7 milliseconds) - * 3. DBG pin must be high before chip exits reset for normal - * operation. DBG is open drain and hopefully pulled high - * since we don't normally drive it (GPIO 1?) for the - * HVR-1600 - * 4. Z8F0811 won't exit reset until RESET is deasserted - * 5. Zilog comes out of reset, loads reset vector address and - * executes from there. Required recovery delay unknown. - */ - gpio_reset_seq(cx, p->ir_reset_mask, 0, - p->msecs_asserted, p->msecs_recovery); - break; - case CX18_GPIO_RESET_XC2028: - if (cx->card->tuners[0].tuner == TUNER_XC2028) - gpio_reset_seq(cx, (1 << cx->card->xceive_pin), 0, - 1, 1); - break; - } - return 0; -} - -static const struct v4l2_subdev_core_ops resetctrl_core_ops = { - .log_status = resetctrl_log_status, - .reset = resetctrl_reset, -}; - -static const struct v4l2_subdev_ops resetctrl_ops = { - .core = &resetctrl_core_ops, -}; - -/* - * External entry points - */ -void cx18_gpio_init(struct cx18 *cx) -{ - mutex_lock(&cx->gpio_lock); - cx->gpio_dir = cx->card->gpio_init.direction; - cx->gpio_val = cx->card->gpio_init.initial_value; - - if (cx->card->tuners[0].tuner == TUNER_XC2028) { - cx->gpio_dir |= 1 << cx->card->xceive_pin; - cx->gpio_val |= 1 << cx->card->xceive_pin; - } - - if (cx->gpio_dir == 0) { - mutex_unlock(&cx->gpio_lock); - return; - } - - CX18_DEBUG_INFO("GPIO initial dir: %08x/%08x out: %08x/%08x\n", - cx18_read_reg(cx, CX18_REG_GPIO_DIR1), - cx18_read_reg(cx, CX18_REG_GPIO_DIR2), - cx18_read_reg(cx, CX18_REG_GPIO_OUT1), - cx18_read_reg(cx, CX18_REG_GPIO_OUT2)); - - gpio_write(cx); - mutex_unlock(&cx->gpio_lock); -} - -int cx18_gpio_register(struct cx18 *cx, u32 hw) -{ - struct v4l2_subdev *sd; - const struct v4l2_subdev_ops *ops; - char *str; - - switch (hw) { - case CX18_HW_GPIO_MUX: - sd = &cx->sd_gpiomux; - ops = &gpiomux_ops; - str = "gpio-mux"; - break; - case CX18_HW_GPIO_RESET_CTRL: - sd = &cx->sd_resetctrl; - ops = &resetctrl_ops; - str = "gpio-reset-ctrl"; - break; - default: - return -EINVAL; - } - - v4l2_subdev_init(sd, ops); - v4l2_set_subdevdata(sd, cx); - snprintf(sd->name, sizeof(sd->name), "%s %s", cx->v4l2_dev.name, str); - sd->grp_id = hw; - return v4l2_device_register_subdev(&cx->v4l2_dev, sd); -} - -void cx18_reset_ir_gpio(void *data) -{ - struct cx18 *cx = to_cx18((struct v4l2_device *)data); - - if (cx->card->gpio_i2c_slave_reset.ir_reset_mask == 0) - return; - - CX18_DEBUG_INFO("Resetting IR microcontroller\n"); - - v4l2_subdev_call(&cx->sd_resetctrl, - core, reset, CX18_GPIO_RESET_Z8F0811); -} -EXPORT_SYMBOL(cx18_reset_ir_gpio); -/* This symbol is exported for use by lirc_pvr150 for the IR-blaster */ - -/* Xceive tuner reset function */ -int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value) -{ - struct i2c_algo_bit_data *algo = dev; - struct cx18_i2c_algo_callback_data *cb_data = algo->data; - struct cx18 *cx = cb_data->cx; - - if (cmd != XC2028_TUNER_RESET || - cx->card->tuners[0].tuner != TUNER_XC2028) - return 0; - - CX18_DEBUG_INFO("Resetting XCeive tuner\n"); - return v4l2_subdev_call(&cx->sd_resetctrl, - core, reset, CX18_GPIO_RESET_XC2028); -} diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h deleted file mode 100644 index 4aea2ef88e8..00000000000 --- a/drivers/media/video/cx18/cx18-gpio.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * cx18 gpio functions - * - * Derived from ivtv-gpio.h - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -void cx18_gpio_init(struct cx18 *cx); -int cx18_gpio_register(struct cx18 *cx, u32 hw); - -enum cx18_gpio_reset_type { - CX18_GPIO_RESET_I2C = 0, - CX18_GPIO_RESET_Z8F0811 = 1, - CX18_GPIO_RESET_XC2028 = 2, -}; - -void cx18_reset_ir_gpio(void *data); -int cx18_reset_tuner_gpio(void *dev, int component, int cmd, int value); diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c deleted file mode 100644 index 51609d5c88c..00000000000 --- a/drivers/media/video/cx18/cx18-i2c.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * cx18 I2C functions - * - * Derived from ivtv-i2c.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-cards.h" -#include "cx18-gpio.h" -#include "cx18-i2c.h" -#include "cx18-irq.h" - -#define CX18_REG_I2C_1_WR 0xf15000 -#define CX18_REG_I2C_1_RD 0xf15008 -#define CX18_REG_I2C_2_WR 0xf25100 -#define CX18_REG_I2C_2_RD 0xf25108 - -#define SETSCL_BIT 0x0001 -#define SETSDL_BIT 0x0002 -#define GETSCL_BIT 0x0004 -#define GETSDL_BIT 0x0008 - -#define CX18_CS5345_I2C_ADDR 0x4c -#define CX18_Z8F0811_IR_TX_I2C_ADDR 0x70 -#define CX18_Z8F0811_IR_RX_I2C_ADDR 0x71 - -/* This array should match the CX18_HW_ defines */ -static const u8 hw_addrs[] = { - 0, /* CX18_HW_TUNER */ - 0, /* CX18_HW_TVEEPROM */ - CX18_CS5345_I2C_ADDR, /* CX18_HW_CS5345 */ - 0, /* CX18_HW_DVB */ - 0, /* CX18_HW_418_AV */ - 0, /* CX18_HW_GPIO_MUX */ - 0, /* CX18_HW_GPIO_RESET_CTRL */ - CX18_Z8F0811_IR_TX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_TX_HAUP */ - CX18_Z8F0811_IR_RX_I2C_ADDR, /* CX18_HW_Z8F0811_IR_RX_HAUP */ -}; - -/* This array should match the CX18_HW_ defines */ -/* This might well become a card-specific array */ -static const u8 hw_bus[] = { - 1, /* CX18_HW_TUNER */ - 0, /* CX18_HW_TVEEPROM */ - 0, /* CX18_HW_CS5345 */ - 0, /* CX18_HW_DVB */ - 0, /* CX18_HW_418_AV */ - 0, /* CX18_HW_GPIO_MUX */ - 0, /* CX18_HW_GPIO_RESET_CTRL */ - 0, /* CX18_HW_Z8F0811_IR_TX_HAUP */ - 0, /* CX18_HW_Z8F0811_IR_RX_HAUP */ -}; - -/* This array should match the CX18_HW_ defines */ -static const char * const hw_devicenames[] = { - "tuner", - "tveeprom", - "cs5345", - "cx23418_DTV", - "cx23418_AV", - "gpio_mux", - "gpio_reset_ctrl", - "ir_tx_z8f0811_haup", - "ir_rx_z8f0811_haup", -}; - -static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw, - const char *type, u8 addr) -{ - struct i2c_board_info info; - struct IR_i2c_init_data *init_data = &cx->ir_i2c_init_data; - unsigned short addr_list[2] = { addr, I2C_CLIENT_END }; - - memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, type, I2C_NAME_SIZE); - - /* Our default information for ir-kbd-i2c.c to use */ - switch (hw) { - case CX18_HW_Z8F0811_IR_RX_HAUP: - init_data->ir_codes = RC_MAP_HAUPPAUGE; - init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR; - init_data->type = RC_TYPE_RC5; - init_data->name = cx->card_name; - info.platform_data = init_data; - break; - } - - return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ? - -1 : 0; -} - -int cx18_i2c_register(struct cx18 *cx, unsigned idx) -{ - struct v4l2_subdev *sd; - int bus = hw_bus[idx]; - struct i2c_adapter *adap = &cx->i2c_adap[bus]; - const char *type = hw_devicenames[idx]; - u32 hw = 1 << idx; - - if (idx >= ARRAY_SIZE(hw_addrs)) - return -1; - - if (hw == CX18_HW_TUNER) { - /* special tuner group handling */ - sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, - adap, type, 0, cx->card_i2c->radio); - if (sd != NULL) - sd->grp_id = hw; - sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, - adap, type, 0, cx->card_i2c->demod); - if (sd != NULL) - sd->grp_id = hw; - sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, - adap, type, 0, cx->card_i2c->tv); - if (sd != NULL) - sd->grp_id = hw; - return sd != NULL ? 0 : -1; - } - - if (hw & CX18_HW_IR_ANY) - return cx18_i2c_new_ir(cx, adap, hw, type, hw_addrs[idx]); - - /* Is it not an I2C device or one we do not wish to register? */ - if (!hw_addrs[idx]) - return -1; - - /* It's an I2C device other than an analog tuner or IR chip */ - sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, type, hw_addrs[idx], - NULL); - if (sd != NULL) - sd->grp_id = hw; - return sd != NULL ? 0 : -1; -} - -/* Find the first member of the subdev group id in hw */ -struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw) -{ - struct v4l2_subdev *result = NULL; - struct v4l2_subdev *sd; - - spin_lock(&cx->v4l2_dev.lock); - v4l2_device_for_each_subdev(sd, &cx->v4l2_dev) { - if (sd->grp_id == hw) { - result = sd; - break; - } - } - spin_unlock(&cx->v4l2_dev.lock); - return result; -} - -static void cx18_setscl(void *data, int state) -{ - struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; - int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; - u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; - u32 r = cx18_read_reg(cx, addr); - - if (state) - cx18_write_reg(cx, r | SETSCL_BIT, addr); - else - cx18_write_reg(cx, r & ~SETSCL_BIT, addr); -} - -static void cx18_setsda(void *data, int state) -{ - struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; - int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; - u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR; - u32 r = cx18_read_reg(cx, addr); - - if (state) - cx18_write_reg(cx, r | SETSDL_BIT, addr); - else - cx18_write_reg(cx, r & ~SETSDL_BIT, addr); -} - -static int cx18_getscl(void *data) -{ - struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; - int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; - u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; - - return cx18_read_reg(cx, addr) & GETSCL_BIT; -} - -static int cx18_getsda(void *data) -{ - struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx; - int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index; - u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD; - - return cx18_read_reg(cx, addr) & GETSDL_BIT; -} - -/* template for i2c-bit-algo */ -static struct i2c_adapter cx18_i2c_adap_template = { - .name = "cx18 i2c driver", - .algo = NULL, /* set by i2c-algo-bit */ - .algo_data = NULL, /* filled from template */ - .owner = THIS_MODULE, -}; - -#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */ -#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */ - -static struct i2c_algo_bit_data cx18_i2c_algo_template = { - .setsda = cx18_setsda, - .setscl = cx18_setscl, - .getsda = cx18_getsda, - .getscl = cx18_getscl, - .udelay = CX18_SCL_PERIOD/2, /* 1/2 clock period in usec*/ - .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */ -}; - -/* init + register i2c adapter */ -int init_cx18_i2c(struct cx18 *cx) -{ - int i, err; - CX18_DEBUG_I2C("i2c init\n"); - - for (i = 0; i < 2; i++) { - /* Setup algorithm for adapter */ - memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template, - sizeof(struct i2c_algo_bit_data)); - cx->i2c_algo_cb_data[i].cx = cx; - cx->i2c_algo_cb_data[i].bus_index = i; - cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i]; - - /* Setup adapter */ - memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template, - sizeof(struct i2c_adapter)); - cx->i2c_adap[i].algo_data = &cx->i2c_algo[i]; - sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name), - " #%d-%d", cx->instance, i); - i2c_set_adapdata(&cx->i2c_adap[i], &cx->v4l2_dev); - cx->i2c_adap[i].dev.parent = &cx->pci_dev->dev; - } - - if (cx18_read_reg(cx, CX18_REG_I2C_2_WR) != 0x0003c02f) { - /* Reset/Unreset I2C hardware block */ - /* Clock select 220MHz */ - cx18_write_reg_expect(cx, 0x10000000, 0xc71004, - 0x00000000, 0x10001000); - /* Clock Enable */ - cx18_write_reg_expect(cx, 0x10001000, 0xc71024, - 0x00001000, 0x10001000); - } - /* courtesy of Steven Toth <stoth@hauppauge.com> */ - cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0); - mdelay(10); - cx18_write_reg_expect(cx, 0x00c000c0, 0xc7001c, 0x000000c0, 0x00c000c0); - mdelay(10); - cx18_write_reg_expect(cx, 0x00c00000, 0xc7001c, 0x00000000, 0x00c000c0); - mdelay(10); - - /* Set to edge-triggered intrs. */ - cx18_write_reg(cx, 0x00c00000, 0xc730c8); - /* Clear any stale intrs */ - cx18_write_reg_expect(cx, HW2_I2C1_INT|HW2_I2C2_INT, HW2_INT_CLR_STATUS, - ~(HW2_I2C1_INT|HW2_I2C2_INT), HW2_I2C1_INT|HW2_I2C2_INT); - - /* Hw I2C1 Clock Freq ~100kHz */ - cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_1_WR); - cx18_setscl(&cx->i2c_algo_cb_data[0], 1); - cx18_setsda(&cx->i2c_algo_cb_data[0], 1); - - /* Hw I2C2 Clock Freq ~100kHz */ - cx18_write_reg(cx, 0x00021c0f & ~4, CX18_REG_I2C_2_WR); - cx18_setscl(&cx->i2c_algo_cb_data[1], 1); - cx18_setsda(&cx->i2c_algo_cb_data[1], 1); - - cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, - core, reset, (u32) CX18_GPIO_RESET_I2C); - - err = i2c_bit_add_bus(&cx->i2c_adap[0]); - if (err) - goto err; - err = i2c_bit_add_bus(&cx->i2c_adap[1]); - if (err) - goto err_del_bus_0; - return 0; - - err_del_bus_0: - i2c_del_adapter(&cx->i2c_adap[0]); - err: - return err; -} - -void exit_cx18_i2c(struct cx18 *cx) -{ - int i; - CX18_DEBUG_I2C("i2c exit\n"); - cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_1_WR) | 4, - CX18_REG_I2C_1_WR); - cx18_write_reg(cx, cx18_read_reg(cx, CX18_REG_I2C_2_WR) | 4, - CX18_REG_I2C_2_WR); - - for (i = 0; i < 2; i++) { - i2c_del_adapter(&cx->i2c_adap[i]); - } -} - -/* - Hauppauge HVR1600 should have: - 32 cx24227 - 98 unknown - a0 eeprom - c2 tuner - e? zilog ir - */ diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h deleted file mode 100644 index 1180fdc8d98..00000000000 --- a/drivers/media/video/cx18/cx18-i2c.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * cx18 I2C functions - * - * Derived from ivtv-i2c.h - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -int cx18_i2c_register(struct cx18 *cx, unsigned idx); -struct v4l2_subdev *cx18_find_hw(struct cx18 *cx, u32 hw); - -/* init + register i2c adapter */ -int init_cx18_i2c(struct cx18 *cx); -void exit_cx18_i2c(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c deleted file mode 100644 index 49b9dbd0624..00000000000 --- a/drivers/media/video/cx18/cx18-io.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * cx18 driver PCI memory mapped IO access routines - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-irq.h" - -void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count) -{ - u8 __iomem *dst = addr; - u16 val2 = val | (val << 8); - u32 val4 = val2 | (val2 << 16); - - /* Align writes on the CX23418's addresses */ - if ((count > 0) && ((unsigned long)dst & 1)) { - cx18_writeb(cx, (u8) val, dst); - count--; - dst++; - } - if ((count > 1) && ((unsigned long)dst & 2)) { - cx18_writew(cx, val2, dst); - count -= 2; - dst += 2; - } - while (count > 3) { - cx18_writel(cx, val4, dst); - count -= 4; - dst += 4; - } - if (count > 1) { - cx18_writew(cx, val2, dst); - count -= 2; - dst += 2; - } - if (count > 0) - cx18_writeb(cx, (u8) val, dst); -} - -void cx18_sw1_irq_enable(struct cx18 *cx, u32 val) -{ - cx18_write_reg_expect(cx, val, SW1_INT_STATUS, ~val, val); - cx->sw1_irq_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) | val; - cx18_write_reg(cx, cx->sw1_irq_mask, SW1_INT_ENABLE_PCI); -} - -void cx18_sw1_irq_disable(struct cx18 *cx, u32 val) -{ - cx->sw1_irq_mask = cx18_read_reg(cx, SW1_INT_ENABLE_PCI) & ~val; - cx18_write_reg(cx, cx->sw1_irq_mask, SW1_INT_ENABLE_PCI); -} - -void cx18_sw2_irq_enable(struct cx18 *cx, u32 val) -{ - cx18_write_reg_expect(cx, val, SW2_INT_STATUS, ~val, val); - cx->sw2_irq_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) | val; - cx18_write_reg(cx, cx->sw2_irq_mask, SW2_INT_ENABLE_PCI); -} - -void cx18_sw2_irq_disable(struct cx18 *cx, u32 val) -{ - cx->sw2_irq_mask = cx18_read_reg(cx, SW2_INT_ENABLE_PCI) & ~val; - cx18_write_reg(cx, cx->sw2_irq_mask, SW2_INT_ENABLE_PCI); -} - -void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val) -{ - u32 r; - r = cx18_read_reg(cx, SW2_INT_ENABLE_CPU); - cx18_write_reg(cx, r & ~val, SW2_INT_ENABLE_CPU); -} - -void cx18_setup_page(struct cx18 *cx, u32 addr) -{ - u32 val; - val = cx18_read_reg(cx, 0xD000F8); - val = (val & ~0x1f00) | ((addr >> 17) & 0x1f00); - cx18_write_reg(cx, val, 0xD000F8); -} diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/video/cx18/cx18-io.h deleted file mode 100644 index 18974d886cf..00000000000 --- a/drivers/media/video/cx18/cx18-io.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * cx18 driver PCI memory mapped IO access routines - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#ifndef CX18_IO_H -#define CX18_IO_H - -#include "cx18-driver.h" - -/* - * Readback and retry of MMIO access for reliability: - * The concept was suggested by Steve Toth <stoth@linuxtv.org>. - * The implmentation is the fault of Andy Walls <awalls@md.metrocast.net>. - * - * *write* functions are implied to retry the mmio unless suffixed with _noretry - * *read* functions never retry the mmio (it never helps to do so) - */ - -/* Non byteswapping memory mapped IO */ -static inline u32 cx18_raw_readl(struct cx18 *cx, const void __iomem *addr) -{ - return __raw_readl(addr); -} - -static inline -void cx18_raw_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr) -{ - __raw_writel(val, addr); -} - -static inline void cx18_raw_writel(struct cx18 *cx, u32 val, void __iomem *addr) -{ - int i; - for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { - cx18_raw_writel_noretry(cx, val, addr); - if (val == cx18_raw_readl(cx, addr)) - break; - } -} - -/* Normal memory mapped IO */ -static inline u32 cx18_readl(struct cx18 *cx, const void __iomem *addr) -{ - return readl(addr); -} - -static inline -void cx18_writel_noretry(struct cx18 *cx, u32 val, void __iomem *addr) -{ - writel(val, addr); -} - -static inline void cx18_writel(struct cx18 *cx, u32 val, void __iomem *addr) -{ - int i; - for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { - cx18_writel_noretry(cx, val, addr); - if (val == cx18_readl(cx, addr)) - break; - } -} - -static inline -void cx18_writel_expect(struct cx18 *cx, u32 val, void __iomem *addr, - u32 eval, u32 mask) -{ - int i; - u32 r; - eval &= mask; - for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { - cx18_writel_noretry(cx, val, addr); - r = cx18_readl(cx, addr); - if (r == 0xffffffff && eval != 0xffffffff) - continue; - if (eval == (r & mask)) - break; - } -} - -static inline u16 cx18_readw(struct cx18 *cx, const void __iomem *addr) -{ - return readw(addr); -} - -static inline -void cx18_writew_noretry(struct cx18 *cx, u16 val, void __iomem *addr) -{ - writew(val, addr); -} - -static inline void cx18_writew(struct cx18 *cx, u16 val, void __iomem *addr) -{ - int i; - for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { - cx18_writew_noretry(cx, val, addr); - if (val == cx18_readw(cx, addr)) - break; - } -} - -static inline u8 cx18_readb(struct cx18 *cx, const void __iomem *addr) -{ - return readb(addr); -} - -static inline -void cx18_writeb_noretry(struct cx18 *cx, u8 val, void __iomem *addr) -{ - writeb(val, addr); -} - -static inline void cx18_writeb(struct cx18 *cx, u8 val, void __iomem *addr) -{ - int i; - for (i = 0; i < CX18_MAX_MMIO_WR_RETRIES; i++) { - cx18_writeb_noretry(cx, val, addr); - if (val == cx18_readb(cx, addr)) - break; - } -} - -static inline -void cx18_memcpy_fromio(struct cx18 *cx, void *to, - const void __iomem *from, unsigned int len) -{ - memcpy_fromio(to, from, len); -} - -void cx18_memset_io(struct cx18 *cx, void __iomem *addr, int val, size_t count); - - -/* Access "register" region of CX23418 memory mapped I/O */ -static inline void cx18_write_reg_noretry(struct cx18 *cx, u32 val, u32 reg) -{ - cx18_writel_noretry(cx, val, cx->reg_mem + reg); -} - -static inline void cx18_write_reg(struct cx18 *cx, u32 val, u32 reg) -{ - cx18_writel(cx, val, cx->reg_mem + reg); -} - -static inline void cx18_write_reg_expect(struct cx18 *cx, u32 val, u32 reg, - u32 eval, u32 mask) -{ - cx18_writel_expect(cx, val, cx->reg_mem + reg, eval, mask); -} - -static inline u32 cx18_read_reg(struct cx18 *cx, u32 reg) -{ - return cx18_readl(cx, cx->reg_mem + reg); -} - - -/* Access "encoder memory" region of CX23418 memory mapped I/O */ -static inline void cx18_write_enc(struct cx18 *cx, u32 val, u32 addr) -{ - cx18_writel(cx, val, cx->enc_mem + addr); -} - -static inline u32 cx18_read_enc(struct cx18 *cx, u32 addr) -{ - return cx18_readl(cx, cx->enc_mem + addr); -} - -void cx18_sw1_irq_enable(struct cx18 *cx, u32 val); -void cx18_sw1_irq_disable(struct cx18 *cx, u32 val); -void cx18_sw2_irq_enable(struct cx18 *cx, u32 val); -void cx18_sw2_irq_disable(struct cx18 *cx, u32 val); -void cx18_sw2_irq_disable_cpu(struct cx18 *cx, u32 val); -void cx18_setup_page(struct cx18 *cx, u32 addr); - -#endif /* CX18_IO_H */ diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c deleted file mode 100644 index e9912db3b49..00000000000 --- a/drivers/media/video/cx18/cx18-ioctl.c +++ /dev/null @@ -1,1194 +0,0 @@ -/* - * cx18 ioctl system call - * - * Derived from ivtv-ioctl.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-version.h" -#include "cx18-mailbox.h" -#include "cx18-i2c.h" -#include "cx18-queue.h" -#include "cx18-fileops.h" -#include "cx18-vbi.h" -#include "cx18-audio.h" -#include "cx18-video.h" -#include "cx18-streams.h" -#include "cx18-ioctl.h" -#include "cx18-gpio.h" -#include "cx18-controls.h" -#include "cx18-cards.h" -#include "cx18-av-core.h" -#include <media/tveeprom.h> -#include <media/v4l2-chip-ident.h> - -u16 cx18_service2vbi(int type) -{ - switch (type) { - case V4L2_SLICED_TELETEXT_B: - return CX18_SLICED_TYPE_TELETEXT_B; - case V4L2_SLICED_CAPTION_525: - return CX18_SLICED_TYPE_CAPTION_525; - case V4L2_SLICED_WSS_625: - return CX18_SLICED_TYPE_WSS_625; - case V4L2_SLICED_VPS: - return CX18_SLICED_TYPE_VPS; - default: - return 0; - } -} - -/* Check if VBI services are allowed on the (field, line) for the video std */ -static int valid_service_line(int field, int line, int is_pal) -{ - return (is_pal && line >= 6 && - ((field == 0 && line <= 23) || (field == 1 && line <= 22))) || - (!is_pal && line >= 10 && line < 22); -} - -/* - * For a (field, line, std) and inbound potential set of services for that line, - * return the first valid service of those passed in the incoming set for that - * line in priority order: - * CC, VPS, or WSS over TELETEXT for well known lines - * TELETEXT, before VPS, before CC, before WSS, for other lines - */ -static u16 select_service_from_set(int field, int line, u16 set, int is_pal) -{ - u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525); - int i; - - set = set & valid_set; - if (set == 0 || !valid_service_line(field, line, is_pal)) - return 0; - if (!is_pal) { - if (line == 21 && (set & V4L2_SLICED_CAPTION_525)) - return V4L2_SLICED_CAPTION_525; - } else { - if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS)) - return V4L2_SLICED_VPS; - if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625)) - return V4L2_SLICED_WSS_625; - if (line == 23) - return 0; - } - for (i = 0; i < 32; i++) { - if ((1 << i) & set) - return 1 << i; - } - return 0; -} - -/* - * Expand the service_set of *fmt into valid service_lines for the std, - * and clear the passed in fmt->service_set - */ -void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) -{ - u16 set = fmt->service_set; - int f, l; - - fmt->service_set = 0; - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) - fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal); - } -} - -/* - * Sanitize the service_lines in *fmt per the video std, and return 1 - * if any service_line is left as valid after santization - */ -static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal) -{ - int f, l; - u16 set = 0; - - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal); - set |= fmt->service_lines[f][l]; - } - } - return set != 0; -} - -/* Compute the service_set from the assumed valid service_lines of *fmt */ -u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) -{ - int f, l; - u16 set = 0; - - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) - set |= fmt->service_lines[f][l]; - } - return set; -} - -static int cx18_g_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - - pixfmt->width = cx->cxhdl.width; - pixfmt->height = cx->cxhdl.height; - pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - pixfmt->field = V4L2_FIELD_INTERLACED; - pixfmt->priv = 0; - if (id->type == CX18_ENC_STREAM_TYPE_YUV) { - pixfmt->pixelformat = s->pixelformat; - pixfmt->sizeimage = s->vb_bytes_per_frame; - pixfmt->bytesperline = 720; - } else { - pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; - pixfmt->sizeimage = 128 * 1024; - pixfmt->bytesperline = 0; - } - return 0; -} - -static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18 *cx = fh2id(fh)->cx; - struct v4l2_vbi_format *vbifmt = &fmt->fmt.vbi; - - vbifmt->sampling_rate = 27000000; - vbifmt->offset = 248; /* FIXME - slightly wrong for both 50 & 60 Hz */ - vbifmt->samples_per_line = vbi_active_samples - 4; - vbifmt->sample_format = V4L2_PIX_FMT_GREY; - vbifmt->start[0] = cx->vbi.start[0]; - vbifmt->start[1] = cx->vbi.start[1]; - vbifmt->count[0] = vbifmt->count[1] = cx->vbi.count; - vbifmt->flags = 0; - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - return 0; -} - -static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18 *cx = fh2id(fh)->cx; - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - - /* sane, V4L2 spec compliant, defaults */ - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines)); - vbifmt->service_set = 0; - - /* - * Fetch the configured service_lines and total service_set from the - * digitizer/slicer. Note, cx18_av_vbi() wipes the passed in - * fmt->fmt.sliced under valid calling conditions - */ - if (v4l2_subdev_call(cx->sd_av, vbi, g_sliced_fmt, &fmt->fmt.sliced)) - return -EINVAL; - - /* Ensure V4L2 spec compliant output */ - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - vbifmt->service_set = cx18_get_service_set(vbifmt); - return 0; -} - -static int cx18_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - int w = fmt->fmt.pix.width; - int h = fmt->fmt.pix.height; - int min_h = 2; - - w = min(w, 720); - w = max(w, 2); - if (id->type == CX18_ENC_STREAM_TYPE_YUV) { - /* YUV height must be a multiple of 32 */ - h &= ~0x1f; - min_h = 32; - } - h = min(h, cx->is_50hz ? 576 : 480); - h = max(h, min_h); - - fmt->fmt.pix.width = w; - fmt->fmt.pix.height = h; - return 0; -} - -static int cx18_try_fmt_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - return cx18_g_fmt_vbi_cap(file, fh, fmt); -} - -static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18 *cx = fh2id(fh)->cx; - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - - vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - vbifmt->reserved[0] = 0; - vbifmt->reserved[1] = 0; - - /* If given a service set, expand it validly & clear passed in set */ - if (vbifmt->service_set) - cx18_expand_service_set(vbifmt, cx->is_50hz); - /* Sanitize the service_lines, and compute the new set if any valid */ - if (check_service_set(vbifmt, cx->is_50hz)) - vbifmt->service_set = cx18_get_service_set(vbifmt); - return 0; -} - -static int cx18_s_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - struct v4l2_mbus_framefmt mbus_fmt; - struct cx18_stream *s = &cx->streams[id->type]; - int ret; - int w, h; - - ret = cx18_try_fmt_vid_cap(file, fh, fmt); - if (ret) - return ret; - w = fmt->fmt.pix.width; - h = fmt->fmt.pix.height; - - if (cx->cxhdl.width == w && cx->cxhdl.height == h && - s->pixelformat == fmt->fmt.pix.pixelformat) - return 0; - - if (atomic_read(&cx->ana_capturing) > 0) - return -EBUSY; - - s->pixelformat = fmt->fmt.pix.pixelformat; - /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) - UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) - s->vb_bytes_per_frame = h * 720 * 3 / 2; - else - s->vb_bytes_per_frame = h * 720 * 2; - - mbus_fmt.width = cx->cxhdl.width = w; - mbus_fmt.height = cx->cxhdl.height = h; - mbus_fmt.code = V4L2_MBUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt); - return cx18_g_fmt_vid_cap(file, fh, fmt); -} - -static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - int ret; - - /* - * Changing the Encoder's Raw VBI parameters won't have any effect - * if any analog capture is ongoing - */ - if (!cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) - return -EBUSY; - - /* - * Set the digitizer registers for raw active VBI. - * Note cx18_av_vbi_wipes out a lot of the passed in fmt under valid - * calling conditions - */ - ret = v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &fmt->fmt.vbi); - if (ret) - return ret; - - /* Store our new v4l2 (non-)sliced VBI state */ - cx->vbi.sliced_in->service_set = 0; - cx->vbi.in.type = V4L2_BUF_TYPE_VBI_CAPTURE; - - return cx18_g_fmt_vbi_cap(file, fh, fmt); -} - -static int cx18_s_fmt_sliced_vbi_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - int ret; - struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced; - - cx18_try_fmt_sliced_vbi_cap(file, fh, fmt); - - /* - * Changing the Encoder's Raw VBI parameters won't have any effect - * if any analog capture is ongoing - */ - if (cx18_raw_vbi(cx) && atomic_read(&cx->ana_capturing) > 0) - return -EBUSY; - - /* - * Set the service_lines requested in the digitizer/slicer registers. - * Note, cx18_av_vbi() wipes some "impossible" service lines in the - * passed in fmt->fmt.sliced under valid calling conditions - */ - ret = v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &fmt->fmt.sliced); - if (ret) - return ret; - /* Store our current v4l2 sliced VBI settings */ - cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; - memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in)); - return 0; -} - -static int cx18_g_chip_ident(struct file *file, void *fh, - struct v4l2_dbg_chip_ident *chip) -{ - struct cx18 *cx = fh2id(fh)->cx; - int err = 0; - - chip->ident = V4L2_IDENT_NONE; - chip->revision = 0; - switch (chip->match.type) { - case V4L2_CHIP_MATCH_HOST: - switch (chip->match.addr) { - case 0: - chip->ident = V4L2_IDENT_CX23418; - chip->revision = cx18_read_reg(cx, 0xC72028); - break; - case 1: - /* - * The A/V decoder is always present, but in the rare - * case that the card doesn't have analog, we don't - * use it. We find it w/o using the cx->sd_av pointer - */ - cx18_call_hw(cx, CX18_HW_418_AV, - core, g_chip_ident, chip); - break; - default: - /* - * Could return ident = V4L2_IDENT_UNKNOWN if we had - * other host chips at higher addresses, but we don't - */ - err = -EINVAL; /* per V4L2 spec */ - break; - } - break; - case V4L2_CHIP_MATCH_I2C_DRIVER: - /* If needed, returns V4L2_IDENT_AMBIGUOUS without extra work */ - cx18_call_all(cx, core, g_chip_ident, chip); - break; - case V4L2_CHIP_MATCH_I2C_ADDR: - /* - * We could return V4L2_IDENT_UNKNOWN, but we don't do the work - * to look if a chip is at the address with no driver. That's a - * dangerous thing to do with EEPROMs anyway. - */ - cx18_call_all(cx, core, g_chip_ident, chip); - break; - default: - err = -EINVAL; - break; - } - return err; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg) -{ - struct v4l2_dbg_register *regs = arg; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE) - return -EINVAL; - - regs->size = 4; - if (cmd == VIDIOC_DBG_S_REGISTER) - cx18_write_enc(cx, regs->val, regs->reg); - else - regs->val = cx18_read_enc(cx, regs->reg); - return 0; -} - -static int cx18_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (v4l2_chip_match_host(®->match)) - return cx18_cxc(cx, VIDIOC_DBG_G_REGISTER, reg); - /* FIXME - errors shouldn't be ignored */ - cx18_call_all(cx, core, g_register, reg); - return 0; -} - -static int cx18_s_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (v4l2_chip_match_host(®->match)) - return cx18_cxc(cx, VIDIOC_DBG_S_REGISTER, reg); - /* FIXME - errors shouldn't be ignored */ - cx18_call_all(cx, core, s_register, reg); - return 0; -} -#endif - -static int cx18_querycap(struct file *file, void *fh, - struct v4l2_capability *vcap) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver)); - strlcpy(vcap->card, cx->card_name, sizeof(vcap->card)); - snprintf(vcap->bus_info, sizeof(vcap->bus_info), - "PCI:%s", pci_name(cx->pci_dev)); - vcap->capabilities = cx->v4l2_cap; /* capabilities */ - if (id->type == CX18_ENC_STREAM_TYPE_YUV) - vcap->capabilities |= V4L2_CAP_STREAMING; - return 0; -} - -static int cx18_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) -{ - struct cx18 *cx = fh2id(fh)->cx; - - return cx18_get_audio_input(cx, vin->index, vin); -} - -static int cx18_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) -{ - struct cx18 *cx = fh2id(fh)->cx; - - vin->index = cx->audio_input; - return cx18_get_audio_input(cx, vin->index, vin); -} - -static int cx18_s_audio(struct file *file, void *fh, struct v4l2_audio *vout) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (vout->index >= cx->nof_audio_inputs) - return -EINVAL; - cx->audio_input = vout->index; - cx18_audio_set_io(cx); - return 0; -} - -static int cx18_enum_input(struct file *file, void *fh, struct v4l2_input *vin) -{ - struct cx18 *cx = fh2id(fh)->cx; - - /* set it to defaults from our table */ - return cx18_get_input(cx, vin->index, vin); -} - -static int cx18_cropcap(struct file *file, void *fh, - struct v4l2_cropcap *cropcap) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - cropcap->bounds.height = cx->is_50hz ? 576 : 480; - cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; - cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; - cropcap->defrect = cropcap->bounds; - return 0; -} - -static int cx18_s_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n"); - return -EINVAL; -} - -static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n"); - return -EINVAL; -} - -static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_fmtdesc *fmt) -{ - static const struct v4l2_fmtdesc formats[] = { - { 0, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, - "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12, { 0, 0, 0, 0 } - }, - { 1, V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FMT_FLAG_COMPRESSED, - "MPEG", V4L2_PIX_FMT_MPEG, { 0, 0, 0, 0 } - }, - { 2, V4L2_BUF_TYPE_VIDEO_CAPTURE, 0, - "UYVY 4:2:2", V4L2_PIX_FMT_UYVY, { 0, 0, 0, 0 } - }, - }; - - if (fmt->index > ARRAY_SIZE(formats) - 1) - return -EINVAL; - *fmt = formats[fmt->index]; - return 0; -} - -static int cx18_g_input(struct file *file, void *fh, unsigned int *i) -{ - struct cx18 *cx = fh2id(fh)->cx; - - *i = cx->active_input; - return 0; -} - -int cx18_s_input(struct file *file, void *fh, unsigned int inp) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if (inp >= cx->nof_inputs) - return -EINVAL; - - if (inp == cx->active_input) { - CX18_DEBUG_INFO("Input unchanged\n"); - return 0; - } - - CX18_DEBUG_INFO("Changing input from %d to %d\n", - cx->active_input, inp); - - cx->active_input = inp; - /* Set the audio input to whatever is appropriate for the input type. */ - cx->audio_input = cx->card->video_inputs[inp].audio_index; - - /* prevent others from messing with the streams until - we're finished changing inputs. */ - cx18_mute(cx); - cx18_video_set_io(cx); - cx18_audio_set_io(cx); - cx18_unmute(cx); - return 0; -} - -static int cx18_g_frequency(struct file *file, void *fh, - struct v4l2_frequency *vf) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (vf->tuner != 0) - return -EINVAL; - - cx18_call_all(cx, tuner, g_frequency, vf); - return 0; -} - -int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if (vf->tuner != 0) - return -EINVAL; - - cx18_mute(cx); - CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency); - cx18_call_all(cx, tuner, s_frequency, vf); - cx18_unmute(cx); - return 0; -} - -static int cx18_g_std(struct file *file, void *fh, v4l2_std_id *std) -{ - struct cx18 *cx = fh2id(fh)->cx; - - *std = cx->std; - return 0; -} - -int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if ((*std & V4L2_STD_ALL) == 0) - return -EINVAL; - - if (*std == cx->std) - return 0; - - if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) || - atomic_read(&cx->ana_capturing) > 0) { - /* Switching standard would turn off the radio or mess - with already running streams, prevent that by - returning EBUSY. */ - return -EBUSY; - } - - cx->std = *std; - cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0; - cx->is_50hz = !cx->is_60hz; - cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz); - cx->cxhdl.width = 720; - cx->cxhdl.height = cx->is_50hz ? 576 : 480; - cx->vbi.count = cx->is_50hz ? 18 : 12; - cx->vbi.start[0] = cx->is_50hz ? 6 : 10; - cx->vbi.start[1] = cx->is_50hz ? 318 : 273; - CX18_DEBUG_INFO("Switching standard to %llx.\n", - (unsigned long long) cx->std); - - /* Tuner */ - cx18_call_all(cx, core, s_std, cx->std); - return 0; -} - -static int cx18_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if (vt->index != 0) - return -EINVAL; - - cx18_call_all(cx, tuner, s_tuner, vt); - return 0; -} - -static int cx18_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) -{ - struct cx18 *cx = fh2id(fh)->cx; - - if (vt->index != 0) - return -EINVAL; - - cx18_call_all(cx, tuner, g_tuner, vt); - - if (vt->type == V4L2_TUNER_RADIO) - strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name)); - else - strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name)); - return 0; -} - -static int cx18_g_sliced_vbi_cap(struct file *file, void *fh, - struct v4l2_sliced_vbi_cap *cap) -{ - struct cx18 *cx = fh2id(fh)->cx; - int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525; - int f, l; - - if (cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - - cap->service_set = 0; - for (f = 0; f < 2; f++) { - for (l = 0; l < 24; l++) { - if (valid_service_line(f, l, cx->is_50hz)) { - /* - * We can find all v4l2 supported vbi services - * for the standard, on a valid line for the std - */ - cap->service_lines[f][l] = set; - cap->service_set |= set; - } else - cap->service_lines[f][l] = 0; - } - } - for (f = 0; f < 3; f++) - cap->reserved[f] = 0; - return 0; -} - -static int _cx18_process_idx_data(struct cx18_buffer *buf, - struct v4l2_enc_idx *idx) -{ - int consumed, remaining; - struct v4l2_enc_idx_entry *e_idx; - struct cx18_enc_idx_entry *e_buf; - - /* Frame type lookup: 1=I, 2=P, 4=B */ - const int mapping[8] = { - -1, V4L2_ENC_IDX_FRAME_I, V4L2_ENC_IDX_FRAME_P, - -1, V4L2_ENC_IDX_FRAME_B, -1, -1, -1 - }; - - /* - * Assumption here is that a buf holds an integral number of - * struct cx18_enc_idx_entry objects and is properly aligned. - * This is enforced by the module options on IDX buffer sizes. - */ - remaining = buf->bytesused - buf->readpos; - consumed = 0; - e_idx = &idx->entry[idx->entries]; - e_buf = (struct cx18_enc_idx_entry *) &buf->buf[buf->readpos]; - - while (remaining >= sizeof(struct cx18_enc_idx_entry) && - idx->entries < V4L2_ENC_IDX_ENTRIES) { - - e_idx->offset = (((u64) le32_to_cpu(e_buf->offset_high)) << 32) - | le32_to_cpu(e_buf->offset_low); - - e_idx->pts = (((u64) (le32_to_cpu(e_buf->pts_high) & 1)) << 32) - | le32_to_cpu(e_buf->pts_low); - - e_idx->length = le32_to_cpu(e_buf->length); - - e_idx->flags = mapping[le32_to_cpu(e_buf->flags) & 0x7]; - - e_idx->reserved[0] = 0; - e_idx->reserved[1] = 0; - - idx->entries++; - e_idx = &idx->entry[idx->entries]; - e_buf++; - - remaining -= sizeof(struct cx18_enc_idx_entry); - consumed += sizeof(struct cx18_enc_idx_entry); - } - - /* Swallow any partial entries at the end, if there are any */ - if (remaining > 0 && remaining < sizeof(struct cx18_enc_idx_entry)) - consumed += remaining; - - buf->readpos += consumed; - return consumed; -} - -static int cx18_process_idx_data(struct cx18_stream *s, struct cx18_mdl *mdl, - struct v4l2_enc_idx *idx) -{ - if (s->type != CX18_ENC_STREAM_TYPE_IDX) - return -EINVAL; - - if (mdl->curr_buf == NULL) - mdl->curr_buf = list_first_entry(&mdl->buf_list, - struct cx18_buffer, list); - - if (list_entry_is_past_end(mdl->curr_buf, &mdl->buf_list, list)) { - /* - * For some reason we've exhausted the buffers, but the MDL - * object still said some data was unread. - * Fix that and bail out. - */ - mdl->readpos = mdl->bytesused; - return 0; - } - - list_for_each_entry_from(mdl->curr_buf, &mdl->buf_list, list) { - - /* Skip any empty buffers in the MDL */ - if (mdl->curr_buf->readpos >= mdl->curr_buf->bytesused) - continue; - - mdl->readpos += _cx18_process_idx_data(mdl->curr_buf, idx); - - /* exit when MDL drained or request satisfied */ - if (idx->entries >= V4L2_ENC_IDX_ENTRIES || - mdl->curr_buf->readpos < mdl->curr_buf->bytesused || - mdl->readpos >= mdl->bytesused) - break; - } - return 0; -} - -static int cx18_g_enc_index(struct file *file, void *fh, - struct v4l2_enc_idx *idx) -{ - struct cx18 *cx = fh2id(fh)->cx; - struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - s32 tmp; - struct cx18_mdl *mdl; - - if (!cx18_stream_enabled(s)) /* Module options inhibited IDX stream */ - return -EINVAL; - - /* Compute the best case number of entries we can buffer */ - tmp = s->buffers - - s->bufs_per_mdl * CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN; - if (tmp <= 0) - tmp = 1; - tmp = tmp * s->buf_size / sizeof(struct cx18_enc_idx_entry); - - /* Fill out the header of the return structure */ - idx->entries = 0; - idx->entries_cap = tmp; - memset(idx->reserved, 0, sizeof(idx->reserved)); - - /* Pull IDX MDLs and buffers from q_full and populate the entries */ - do { - mdl = cx18_dequeue(s, &s->q_full); - if (mdl == NULL) /* No more IDX data right now */ - break; - - /* Extract the Index entry data from the MDL and buffers */ - cx18_process_idx_data(s, mdl, idx); - if (mdl->readpos < mdl->bytesused) { - /* We finished with data remaining, push the MDL back */ - cx18_push(s, mdl, &s->q_full); - break; - } - - /* We drained this MDL, schedule it to go to the firmware */ - cx18_enqueue(s, mdl, &s->q_free); - - } while (idx->entries < V4L2_ENC_IDX_ENTRIES); - - /* Tell the work handler to send free IDX MDLs to the firmware */ - cx18_stream_load_fw_queue(s); - return 0; -} - -static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id) -{ - struct videobuf_queue *q = NULL; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - switch (s->vb_type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - q = &s->vbuf_q; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - break; - default: - break; - } - return q; -} - -static int cx18_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - /* Start the hardware only if we're the video device */ - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - if (id->type != CX18_ENC_STREAM_TYPE_YUV) - return -EINVAL; - - /* Establish a buffer timeout */ - mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); - - return videobuf_streamon(cx18_vb_queue(id)); -} - -static int cx18_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - /* Start the hardware only if we're the video device */ - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - if (id->type != CX18_ENC_STREAM_TYPE_YUV) - return -EINVAL; - - return videobuf_streamoff(cx18_vb_queue(id)); -} - -static int cx18_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - return videobuf_reqbufs(cx18_vb_queue(id), rb); -} - -static int cx18_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - return videobuf_querybuf(cx18_vb_queue(id), b); -} - -static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - return videobuf_qbuf(cx18_vb_queue(id), b); -} - -static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK); -} - -static int cx18_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *enc) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - u32 h; - - switch (enc->cmd) { - case V4L2_ENC_CMD_START: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); - enc->flags = 0; - return cx18_start_capture(id); - - case V4L2_ENC_CMD_STOP: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); - enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; - cx18_stop_capture(id, - enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); - break; - - case V4L2_ENC_CMD_PAUSE: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); - enc->flags = 0; - if (!atomic_read(&cx->ana_capturing)) - return -EPERM; - if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) - return 0; - h = cx18_find_handle(cx); - if (h == CX18_INVALID_TASK_HANDLE) { - CX18_ERR("Can't find valid task handle for " - "V4L2_ENC_CMD_PAUSE\n"); - return -EBADFD; - } - cx18_mute(cx); - cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, h); - break; - - case V4L2_ENC_CMD_RESUME: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); - enc->flags = 0; - if (!atomic_read(&cx->ana_capturing)) - return -EPERM; - if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags)) - return 0; - h = cx18_find_handle(cx); - if (h == CX18_INVALID_TASK_HANDLE) { - CX18_ERR("Can't find valid task handle for " - "V4L2_ENC_CMD_RESUME\n"); - return -EBADFD; - } - cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h); - cx18_unmute(cx); - break; - - default: - CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); - return -EINVAL; - } - return 0; -} - -static int cx18_try_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *enc) -{ - struct cx18 *cx = fh2id(fh)->cx; - - switch (enc->cmd) { - case V4L2_ENC_CMD_START: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_START\n"); - enc->flags = 0; - break; - - case V4L2_ENC_CMD_STOP: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); - enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; - break; - - case V4L2_ENC_CMD_PAUSE: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n"); - enc->flags = 0; - break; - - case V4L2_ENC_CMD_RESUME: - CX18_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n"); - enc->flags = 0; - break; - - default: - CX18_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd); - return -EINVAL; - } - return 0; -} - -static int cx18_log_status(struct file *file, void *fh) -{ - struct cx18 *cx = fh2id(fh)->cx; - struct v4l2_input vidin; - struct v4l2_audio audin; - int i; - - CX18_INFO("Version: %s Card: %s\n", CX18_VERSION, cx->card_name); - if (cx->hw_flags & CX18_HW_TVEEPROM) { - struct tveeprom tv; - - cx18_read_eeprom(cx, &tv); - } - cx18_call_all(cx, core, log_status); - cx18_get_input(cx, cx->active_input, &vidin); - cx18_get_audio_input(cx, cx->audio_input, &audin); - CX18_INFO("Video Input: %s\n", vidin.name); - CX18_INFO("Audio Input: %s\n", audin.name); - mutex_lock(&cx->gpio_lock); - CX18_INFO("GPIO: direction 0x%08x, value 0x%08x\n", - cx->gpio_dir, cx->gpio_val); - mutex_unlock(&cx->gpio_lock); - CX18_INFO("Tuner: %s\n", - test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ? "Radio" : "TV"); - v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name); - CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags); - for (i = 0; i < CX18_MAX_STREAMS; i++) { - struct cx18_stream *s = &cx->streams[i]; - - if (s->video_dev == NULL || s->buffers == 0) - continue; - CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", - s->name, s->s_flags, - atomic_read(&s->q_full.depth) * s->bufs_per_mdl * 100 - / s->buffers, - (s->buffers * s->buf_size) / 1024, s->buffers); - } - CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n", - (long long)cx->mpg_data_received, - (long long)cx->vbi_data_inserted); - return 0; -} - -static long cx18_default(struct file *file, void *fh, bool valid_prio, - int cmd, void *arg) -{ - struct cx18 *cx = fh2id(fh)->cx; - - switch (cmd) { - case VIDIOC_INT_RESET: { - u32 val = *(u32 *)arg; - - if ((val == 0) || (val & 0x01)) - cx18_call_hw(cx, CX18_HW_GPIO_RESET_CTRL, core, reset, - (u32) CX18_GPIO_RESET_Z8F0811); - break; - } - - default: - return -ENOTTY; - } - return 0; -} - -static const struct v4l2_ioctl_ops cx18_ioctl_ops = { - .vidioc_querycap = cx18_querycap, - .vidioc_s_audio = cx18_s_audio, - .vidioc_g_audio = cx18_g_audio, - .vidioc_enumaudio = cx18_enumaudio, - .vidioc_enum_input = cx18_enum_input, - .vidioc_cropcap = cx18_cropcap, - .vidioc_s_crop = cx18_s_crop, - .vidioc_g_crop = cx18_g_crop, - .vidioc_g_input = cx18_g_input, - .vidioc_s_input = cx18_s_input, - .vidioc_g_frequency = cx18_g_frequency, - .vidioc_s_frequency = cx18_s_frequency, - .vidioc_s_tuner = cx18_s_tuner, - .vidioc_g_tuner = cx18_g_tuner, - .vidioc_g_enc_index = cx18_g_enc_index, - .vidioc_g_std = cx18_g_std, - .vidioc_s_std = cx18_s_std, - .vidioc_log_status = cx18_log_status, - .vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap, - .vidioc_encoder_cmd = cx18_encoder_cmd, - .vidioc_try_encoder_cmd = cx18_try_encoder_cmd, - .vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap, - .vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap, - .vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap, - .vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap, - .vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap, - .vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap, - .vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap, - .vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap, - .vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap, - .vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap, - .vidioc_g_chip_ident = cx18_g_chip_ident, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = cx18_g_register, - .vidioc_s_register = cx18_s_register, -#endif - .vidioc_default = cx18_default, - .vidioc_streamon = cx18_streamon, - .vidioc_streamoff = cx18_streamoff, - .vidioc_reqbufs = cx18_reqbufs, - .vidioc_querybuf = cx18_querybuf, - .vidioc_qbuf = cx18_qbuf, - .vidioc_dqbuf = cx18_dqbuf, -}; - -void cx18_set_funcs(struct video_device *vdev) -{ - vdev->ioctl_ops = &cx18_ioctl_ops; -} diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h deleted file mode 100644 index 2f9dd591ee0..00000000000 --- a/drivers/media/video/cx18/cx18-ioctl.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * cx18 ioctl system call - * - * Derived from ivtv-ioctl.h - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -u16 cx18_service2vbi(int type); -void cx18_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal); -u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt); -void cx18_set_funcs(struct video_device *vdev); -int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std); -int cx18_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); -int cx18_s_input(struct file *file, void *fh, unsigned int inp); diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c deleted file mode 100644 index 80edfe93a3d..00000000000 --- a/drivers/media/video/cx18/cx18-irq.c +++ /dev/null @@ -1,81 +0,0 @@ -/* - * cx18 interrupt handling - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-irq.h" -#include "cx18-mailbox.h" -#include "cx18-scb.h" - -static void xpu_ack(struct cx18 *cx, u32 sw2) -{ - if (sw2 & IRQ_CPU_TO_EPU_ACK) - wake_up(&cx->mb_cpu_waitq); - if (sw2 & IRQ_APU_TO_EPU_ACK) - wake_up(&cx->mb_apu_waitq); -} - -static void epu_cmd(struct cx18 *cx, u32 sw1) -{ - if (sw1 & IRQ_CPU_TO_EPU) - cx18_api_epu_cmd_irq(cx, CPU); - if (sw1 & IRQ_APU_TO_EPU) - cx18_api_epu_cmd_irq(cx, APU); -} - -irqreturn_t cx18_irq_handler(int irq, void *dev_id) -{ - struct cx18 *cx = (struct cx18 *)dev_id; - u32 sw1, sw2, hw2; - - sw1 = cx18_read_reg(cx, SW1_INT_STATUS) & cx->sw1_irq_mask; - sw2 = cx18_read_reg(cx, SW2_INT_STATUS) & cx->sw2_irq_mask; - hw2 = cx18_read_reg(cx, HW2_INT_CLR_STATUS) & cx->hw2_irq_mask; - - if (sw1) - cx18_write_reg_expect(cx, sw1, SW1_INT_STATUS, ~sw1, sw1); - if (sw2) - cx18_write_reg_expect(cx, sw2, SW2_INT_STATUS, ~sw2, sw2); - if (hw2) - cx18_write_reg_expect(cx, hw2, HW2_INT_CLR_STATUS, ~hw2, hw2); - - if (sw1 || sw2 || hw2) - CX18_DEBUG_HI_IRQ("received interrupts " - "SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); - - /* - * SW1 responses have to happen first. The sending XPU times out the - * incoming mailboxes on us rather rapidly. - */ - if (sw1) - epu_cmd(cx, sw1); - - /* To do: interrupt-based I2C handling - if (hw2 & (HW2_I2C1_INT|HW2_I2C2_INT)) { - } - */ - - if (sw2) - xpu_ack(cx, sw2); - - return (sw1 || sw2 || hw2) ? IRQ_HANDLED : IRQ_NONE; -} diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h deleted file mode 100644 index 30e7eaf8cb5..00000000000 --- a/drivers/media/video/cx18/cx18-irq.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * cx18 interrupt handling - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#define HW2_I2C1_INT (1 << 22) -#define HW2_I2C2_INT (1 << 23) -#define HW2_INT_CLR_STATUS 0xc730c4 -#define HW2_INT_MASK5_PCI 0xc730e4 -#define SW1_INT_SET 0xc73100 -#define SW1_INT_STATUS 0xc73104 -#define SW1_INT_ENABLE_PCI 0xc7311c -#define SW2_INT_SET 0xc73140 -#define SW2_INT_STATUS 0xc73144 -#define SW2_INT_ENABLE_CPU 0xc73158 -#define SW2_INT_ENABLE_PCI 0xc7315c - -irqreturn_t cx18_irq_handler(int irq, void *dev_id); diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c deleted file mode 100644 index eabf00c6351..00000000000 --- a/drivers/media/video/cx18/cx18-mailbox.c +++ /dev/null @@ -1,870 +0,0 @@ -/* - * cx18 mailbox functions - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include <stdarg.h> - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-scb.h" -#include "cx18-irq.h" -#include "cx18-mailbox.h" -#include "cx18-queue.h" -#include "cx18-streams.h" -#include "cx18-alsa-pcm.h" /* FIXME make configurable */ - -static const char *rpu_str[] = { "APU", "CPU", "EPU", "HPU" }; - -#define API_FAST (1 << 2) /* Short timeout */ -#define API_SLOW (1 << 3) /* Additional 300ms timeout */ - -struct cx18_api_info { - u32 cmd; - u8 flags; /* Flags, see above */ - u8 rpu; /* Processing unit */ - const char *name; /* The name of the command */ -}; - -#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x } - -static const struct cx18_api_info api_info[] = { - /* MPEG encoder API */ - API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), - API_ENTRY(CPU, CX18_EPU_DEBUG, 0), - API_ENTRY(CPU, CX18_CREATE_TASK, 0), - API_ENTRY(CPU, CX18_DESTROY_TASK, 0), - API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW), - API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW), - API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0), - API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0), - API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0), - API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0), - API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0), - API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0), - API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0), - API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0), - API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0), - API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0), - API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0), - API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW), - API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0), - API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0), - API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0), - API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0), - API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0), - API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0), - API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0), - API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0), - API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0), - API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0), - API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0), - API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), - API_ENTRY(CPU, CX18_CPU_SET_VFC_PARAM, 0), - API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), - API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), - API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), - API_ENTRY(APU, CX18_APU_START, 0), - API_ENTRY(APU, CX18_APU_STOP, 0), - API_ENTRY(APU, CX18_APU_RESETAI, 0), - API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32, 0), - API_ENTRY(0, 0, 0), -}; - -static const struct cx18_api_info *find_api_info(u32 cmd) -{ - int i; - - for (i = 0; api_info[i].cmd; i++) - if (api_info[i].cmd == cmd) - return &api_info[i]; - return NULL; -} - -/* Call with buf of n*11+1 bytes */ -static char *u32arr2hex(u32 data[], int n, char *buf) -{ - char *p; - int i; - - for (i = 0, p = buf; i < n; i++, p += 11) { - /* kernel snprintf() appends '\0' always */ - snprintf(p, 12, " %#010x", data[i]); - } - *p = '\0'; - return buf; -} - -static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) -{ - char argstr[MAX_MB_ARGUMENTS*11+1]; - - if (!(cx18_debug & CX18_DBGFLG_API)) - return; - - CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s" - "\n", name, mb->request, mb->ack, mb->cmd, mb->error, - u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr)); -} - - -/* - * Functions that run in a work_queue work handling context - */ - -static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - - if (s->dvb == NULL || !s->dvb->enabled || mdl->bytesused == 0) - return; - - /* We ignore mdl and buf readpos accounting here - it doesn't matter */ - - /* The likely case */ - if (list_is_singular(&mdl->buf_list)) { - buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, - list); - if (buf->bytesused) - dvb_dmx_swfilter(&s->dvb->demux, - buf->buf, buf->bytesused); - return; - } - - list_for_each_entry(buf, &mdl->buf_list, list) { - if (buf->bytesused == 0) - break; - dvb_dmx_swfilter(&s->dvb->demux, buf->buf, buf->bytesused); - } -} - -static void cx18_mdl_send_to_videobuf(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - struct cx18_videobuf_buffer *vb_buf; - struct cx18_buffer *buf; - u8 *p; - u32 offset = 0; - int dispatch = 0; - - if (mdl->bytesused == 0) - return; - - /* Acquire a videobuf buffer, clone to and and release it */ - spin_lock(&s->vb_lock); - if (list_empty(&s->vb_capture)) - goto out; - - vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer, - vb.queue); - - p = videobuf_to_vmalloc(&vb_buf->vb); - if (!p) - goto out; - - offset = vb_buf->bytes_used; - list_for_each_entry(buf, &mdl->buf_list, list) { - if (buf->bytesused == 0) - break; - - if ((offset + buf->bytesused) <= vb_buf->vb.bsize) { - memcpy(p + offset, buf->buf, buf->bytesused); - offset += buf->bytesused; - vb_buf->bytes_used += buf->bytesused; - } - } - - /* If we've filled the buffer as per the callers res then dispatch it */ - if (vb_buf->bytes_used >= s->vb_bytes_per_frame) { - dispatch = 1; - vb_buf->bytes_used = 0; - } - - if (dispatch) { - vb_buf->vb.ts = ktime_to_timeval(ktime_get()); - list_del(&vb_buf->vb.queue); - vb_buf->vb.state = VIDEOBUF_DONE; - wake_up(&vb_buf->vb.done); - } - - mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); - -out: - spin_unlock(&s->vb_lock); -} - -static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - - if (mdl->bytesused == 0) - return; - - /* We ignore mdl and buf readpos accounting here - it doesn't matter */ - - /* The likely case */ - if (list_is_singular(&mdl->buf_list)) { - buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, - list); - if (buf->bytesused) - cx->pcm_announce_callback(cx->alsa, buf->buf, - buf->bytesused); - return; - } - - list_for_each_entry(buf, &mdl->buf_list, list) { - if (buf->bytesused == 0) - break; - cx->pcm_announce_callback(cx->alsa, buf->buf, buf->bytesused); - } -} - -static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) -{ - u32 handle, mdl_ack_count, id; - struct cx18_mailbox *mb; - struct cx18_mdl_ack *mdl_ack; - struct cx18_stream *s; - struct cx18_mdl *mdl; - int i; - - mb = &order->mb; - handle = mb->args[0]; - s = cx18_handle_to_stream(cx, handle); - - if (s == NULL) { - CX18_WARN("Got DMA done notification for unknown/inactive" - " handle %d, %s mailbox seq no %d\n", handle, - (order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ? - "stale" : "good", mb->request); - return; - } - - mdl_ack_count = mb->args[2]; - mdl_ack = order->mdl_ack; - for (i = 0; i < mdl_ack_count; i++, mdl_ack++) { - id = mdl_ack->id; - /* - * Simple integrity check for processing a stale (and possibly - * inconsistent mailbox): make sure the MDL id is in the - * valid range for the stream. - * - * We go through the trouble of dealing with stale mailboxes - * because most of the time, the mailbox data is still valid and - * unchanged (and in practice the firmware ping-pongs the - * two mdl_ack buffers so mdl_acks are not stale). - * - * There are occasions when we get a half changed mailbox, - * which this check catches for a handle & id mismatch. If the - * handle and id do correspond, the worst case is that we - * completely lost the old MDL, but pick up the new MDL - * early (but the new mdl_ack is guaranteed to be good in this - * case as the firmware wouldn't point us to a new mdl_ack until - * it's filled in). - * - * cx18_queue_get_mdl() will detect the lost MDLs - * and send them back to q_free for fw rotation eventually. - */ - if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && - !(id >= s->mdl_base_idx && - id < (s->mdl_base_idx + s->buffers))) { - CX18_WARN("Fell behind! Ignoring stale mailbox with " - " inconsistent data. Lost MDL for mailbox " - "seq no %d\n", mb->request); - break; - } - mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used); - - CX18_DEBUG_HI_DMA("DMA DONE for %s (MDL %d)\n", s->name, id); - if (mdl == NULL) { - CX18_WARN("Could not find MDL %d for stream %s\n", - id, s->name); - continue; - } - - CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n", - s->name, mdl->bytesused); - - if (s->type == CX18_ENC_STREAM_TYPE_TS) { - cx18_mdl_send_to_dvb(s, mdl); - cx18_enqueue(s, mdl, &s->q_free); - } else if (s->type == CX18_ENC_STREAM_TYPE_PCM) { - /* Pass the data to cx18-alsa */ - if (cx->pcm_announce_callback != NULL) { - cx18_mdl_send_to_alsa(cx, s, mdl); - cx18_enqueue(s, mdl, &s->q_free); - } else { - cx18_enqueue(s, mdl, &s->q_full); - } - } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) { - cx18_mdl_send_to_videobuf(s, mdl); - cx18_enqueue(s, mdl, &s->q_free); - } else { - cx18_enqueue(s, mdl, &s->q_full); - if (s->type == CX18_ENC_STREAM_TYPE_IDX) - cx18_stream_rotate_idx_mdls(cx); - } - } - /* Put as many MDLs as possible back into fw use */ - cx18_stream_load_fw_queue(s); - - wake_up(&cx->dma_waitq); - if (s->id != -1) - wake_up(&s->waitq); -} - -static void epu_debug(struct cx18 *cx, struct cx18_in_work_order *order) -{ - char *p; - char *str = order->str; - - CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str); - p = strchr(str, '.'); - if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) - CX18_INFO("FW version: %s\n", p - 1); -} - -static void epu_cmd(struct cx18 *cx, struct cx18_in_work_order *order) -{ - switch (order->rpu) { - case CPU: - { - switch (order->mb.cmd) { - case CX18_EPU_DMA_DONE: - epu_dma_done(cx, order); - break; - case CX18_EPU_DEBUG: - epu_debug(cx, order); - break; - default: - CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - } - break; - } - case APU: - CX18_WARN("Unknown APU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - default: - break; - } -} - -static -void free_in_work_order(struct cx18 *cx, struct cx18_in_work_order *order) -{ - atomic_set(&order->pending, 0); -} - -void cx18_in_work_handler(struct work_struct *work) -{ - struct cx18_in_work_order *order = - container_of(work, struct cx18_in_work_order, work); - struct cx18 *cx = order->cx; - epu_cmd(cx, order); - free_in_work_order(cx, order); -} - - -/* - * Functions that run in an interrupt handling context - */ - -static void mb_ack_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - struct cx18_mailbox __iomem *ack_mb; - u32 ack_irq, req; - - switch (order->rpu) { - case APU: - ack_irq = IRQ_EPU_TO_APU_ACK; - ack_mb = &cx->scb->apu2epu_mb; - break; - case CPU: - ack_irq = IRQ_EPU_TO_CPU_ACK; - ack_mb = &cx->scb->cpu2epu_mb; - break; - default: - CX18_WARN("Unhandled RPU (%d) for command %x ack\n", - order->rpu, order->mb.cmd); - return; - } - - req = order->mb.request; - /* Don't ack if the RPU has gotten impatient and timed us out */ - if (req != cx18_readl(cx, &ack_mb->request) || - req == cx18_readl(cx, &ack_mb->ack)) { - CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our " - "incoming %s to EPU mailbox (sequence no. %u) " - "while processing\n", - rpu_str[order->rpu], rpu_str[order->rpu], req); - order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC; - return; - } - cx18_writel(cx, req, &ack_mb->ack); - cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq); - return; -} - -static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - u32 handle, mdl_ack_offset, mdl_ack_count; - struct cx18_mailbox *mb; - int i; - - mb = &order->mb; - handle = mb->args[0]; - mdl_ack_offset = mb->args[1]; - mdl_ack_count = mb->args[2]; - - if (handle == CX18_INVALID_TASK_HANDLE || - mdl_ack_count == 0 || mdl_ack_count > CX18_MAX_MDL_ACKS) { - if ((order->flags & CX18_F_EWO_MB_STALE) == 0) - mb_ack_irq(cx, order); - return -1; - } - - for (i = 0; i < sizeof(struct cx18_mdl_ack) * mdl_ack_count; i += sizeof(u32)) - ((u32 *)order->mdl_ack)[i / sizeof(u32)] = - cx18_readl(cx, cx->enc_mem + mdl_ack_offset + i); - - if ((order->flags & CX18_F_EWO_MB_STALE) == 0) - mb_ack_irq(cx, order); - return 1; -} - -static -int epu_debug_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - u32 str_offset; - char *str = order->str; - - str[0] = '\0'; - str_offset = order->mb.args[1]; - if (str_offset) { - cx18_setup_page(cx, str_offset); - cx18_memcpy_fromio(cx, str, cx->enc_mem + str_offset, 252); - str[252] = '\0'; - cx18_setup_page(cx, SCB_OFFSET); - } - - if ((order->flags & CX18_F_EWO_MB_STALE) == 0) - mb_ack_irq(cx, order); - - return str_offset ? 1 : 0; -} - -static inline -int epu_cmd_irq(struct cx18 *cx, struct cx18_in_work_order *order) -{ - int ret = -1; - - switch (order->rpu) { - case CPU: - { - switch (order->mb.cmd) { - case CX18_EPU_DMA_DONE: - ret = epu_dma_done_irq(cx, order); - break; - case CX18_EPU_DEBUG: - ret = epu_debug_irq(cx, order); - break; - default: - CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - } - break; - } - case APU: - CX18_WARN("Unknown APU to EPU mailbox command %#0x\n", - order->mb.cmd); - break; - default: - break; - } - return ret; -} - -static inline -struct cx18_in_work_order *alloc_in_work_order_irq(struct cx18 *cx) -{ - int i; - struct cx18_in_work_order *order = NULL; - - for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { - /* - * We only need "pending" atomic to inspect its contents, - * and need not do a check and set because: - * 1. Any work handler thread only clears "pending" and only - * on one, particular work order at a time, per handler thread. - * 2. "pending" is only set here, and we're serialized because - * we're called in an IRQ handler context. - */ - if (atomic_read(&cx->in_work_order[i].pending) == 0) { - order = &cx->in_work_order[i]; - atomic_set(&order->pending, 1); - break; - } - } - return order; -} - -void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) -{ - struct cx18_mailbox __iomem *mb; - struct cx18_mailbox *order_mb; - struct cx18_in_work_order *order; - int submit; - int i; - - switch (rpu) { - case CPU: - mb = &cx->scb->cpu2epu_mb; - break; - case APU: - mb = &cx->scb->apu2epu_mb; - break; - default: - return; - } - - order = alloc_in_work_order_irq(cx); - if (order == NULL) { - CX18_WARN("Unable to find blank work order form to schedule " - "incoming mailbox command processing\n"); - return; - } - - order->flags = 0; - order->rpu = rpu; - order_mb = &order->mb; - - /* mb->cmd and mb->args[0] through mb->args[2] */ - for (i = 0; i < 4; i++) - (&order_mb->cmd)[i] = cx18_readl(cx, &mb->cmd + i); - - /* mb->request and mb->ack. N.B. we want to read mb->ack last */ - for (i = 0; i < 2; i++) - (&order_mb->request)[i] = cx18_readl(cx, &mb->request + i); - - if (order_mb->request == order_mb->ack) { - CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our " - "incoming %s to EPU mailbox (sequence no. %u)" - "\n", - rpu_str[rpu], rpu_str[rpu], order_mb->request); - if (cx18_debug & CX18_DBGFLG_WARN) - dump_mb(cx, order_mb, "incoming"); - order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT; - } - - /* - * Individual EPU command processing is responsible for ack-ing - * a non-stale mailbox as soon as possible - */ - submit = epu_cmd_irq(cx, order); - if (submit > 0) { - queue_work(cx->in_work_queue, &order->work); - } -} - - -/* - * Functions called from a non-interrupt, non work_queue context - */ - -static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) -{ - const struct cx18_api_info *info = find_api_info(cmd); - u32 irq, req, ack, err; - struct cx18_mailbox __iomem *mb; - wait_queue_head_t *waitq; - struct mutex *mb_lock; - unsigned long int t0, timeout, ret; - int i; - char argstr[MAX_MB_ARGUMENTS*11+1]; - DEFINE_WAIT(w); - - if (info == NULL) { - CX18_WARN("unknown cmd %x\n", cmd); - return -EINVAL; - } - - if (cx18_debug & CX18_DBGFLG_API) { /* only call u32arr2hex if needed */ - if (cmd == CX18_CPU_DE_SET_MDL) { - if (cx18_debug & CX18_DBGFLG_HIGHVOL) - CX18_DEBUG_HI_API("%s\tcmd %#010x args%s\n", - info->name, cmd, - u32arr2hex(data, args, argstr)); - } else - CX18_DEBUG_API("%s\tcmd %#010x args%s\n", - info->name, cmd, - u32arr2hex(data, args, argstr)); - } - - switch (info->rpu) { - case APU: - waitq = &cx->mb_apu_waitq; - mb_lock = &cx->epu2apu_mb_lock; - irq = IRQ_EPU_TO_APU; - mb = &cx->scb->epu2apu_mb; - break; - case CPU: - waitq = &cx->mb_cpu_waitq; - mb_lock = &cx->epu2cpu_mb_lock; - irq = IRQ_EPU_TO_CPU; - mb = &cx->scb->epu2cpu_mb; - break; - default: - CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu); - return -EINVAL; - } - - mutex_lock(mb_lock); - /* - * Wait for an in-use mailbox to complete - * - * If the XPU is responding with Ack's, the mailbox shouldn't be in - * a busy state, since we serialize access to it on our end. - * - * If the wait for ack after sending a previous command was interrupted - * by a signal, we may get here and find a busy mailbox. After waiting, - * mark it "not busy" from our end, if the XPU hasn't ack'ed it still. - */ - req = cx18_readl(cx, &mb->request); - timeout = msecs_to_jiffies(10); - ret = wait_event_timeout(*waitq, - (ack = cx18_readl(cx, &mb->ack)) == req, - timeout); - if (req != ack) { - /* waited long enough, make the mbox "not busy" from our end */ - cx18_writel(cx, req, &mb->ack); - CX18_ERR("mbox was found stuck busy when setting up for %s; " - "clearing busy and trying to proceed\n", info->name); - } else if (ret != timeout) - CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n", - jiffies_to_msecs(timeout-ret)); - - /* Build the outgoing mailbox */ - req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1; - - cx18_writel(cx, cmd, &mb->cmd); - for (i = 0; i < args; i++) - cx18_writel(cx, data[i], &mb->args[i]); - cx18_writel(cx, 0, &mb->error); - cx18_writel(cx, req, &mb->request); - cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */ - - /* - * Notify the XPU and wait for it to send an Ack back - */ - timeout = msecs_to_jiffies((info->flags & API_FAST) ? 10 : 20); - - CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n", - irq, info->name); - - /* So we don't miss the wakeup, prepare to wait before notifying fw */ - prepare_to_wait(waitq, &w, TASK_UNINTERRUPTIBLE); - cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); - - t0 = jiffies; - ack = cx18_readl(cx, &mb->ack); - if (ack != req) { - schedule_timeout(timeout); - ret = jiffies - t0; - ack = cx18_readl(cx, &mb->ack); - } else { - ret = jiffies - t0; - } - - finish_wait(waitq, &w); - - if (req != ack) { - mutex_unlock(mb_lock); - if (ret >= timeout) { - /* Timed out */ - CX18_DEBUG_WARN("sending %s timed out waiting %d msecs " - "for RPU acknowledgement\n", - info->name, jiffies_to_msecs(ret)); - } else { - CX18_DEBUG_WARN("woken up before mailbox ack was ready " - "after submitting %s to RPU. only " - "waited %d msecs on req %u but awakened" - " with unmatched ack %u\n", - info->name, - jiffies_to_msecs(ret), - req, ack); - } - return -EINVAL; - } - - if (ret >= timeout) - CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment " - "sending %s; timed out waiting %d msecs\n", - info->name, jiffies_to_msecs(ret)); - else - CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", - jiffies_to_msecs(ret), info->name); - - /* Collect data returned by the XPU */ - for (i = 0; i < MAX_MB_ARGUMENTS; i++) - data[i] = cx18_readl(cx, &mb->args[i]); - err = cx18_readl(cx, &mb->error); - mutex_unlock(mb_lock); - - /* - * Wait for XPU to perform extra actions for the caller in some cases. - * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all MDLs - * back in a burst shortly thereafter - */ - if (info->flags & API_SLOW) - cx18_msleep_timeout(300, 0); - - if (err) - CX18_DEBUG_API("mailbox error %08x for command %s\n", err, - info->name); - return err ? -EIO : 0; -} - -int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]) -{ - return cx18_api_call(cx, cmd, args, data); -} - -static int cx18_set_filter_param(struct cx18_stream *s) -{ - struct cx18 *cx = s->cx; - u32 mode; - int ret; - - mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0); - ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, - s->handle, 1, mode, cx->spatial_strength); - mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0); - ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, - s->handle, 0, mode, cx->temporal_strength); - ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4, - s->handle, 2, cx->filter_mode >> 2, 0); - return ret; -} - -int cx18_api_func(void *priv, u32 cmd, int in, int out, - u32 data[CX2341X_MBOX_MAX_DATA]) -{ - struct cx18_stream *s = priv; - struct cx18 *cx = s->cx; - - switch (cmd) { - case CX2341X_ENC_SET_OUTPUT_PORT: - return 0; - case CX2341X_ENC_SET_FRAME_RATE: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6, - s->handle, 0, 0, 0, 0, data[0]); - case CX2341X_ENC_SET_FRAME_SIZE: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3, - s->handle, data[1], data[0]); - case CX2341X_ENC_SET_STREAM_TYPE: - return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2, - s->handle, data[0]); - case CX2341X_ENC_SET_ASPECT_RATIO: - return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2, - s->handle, data[0]); - - case CX2341X_ENC_SET_GOP_PROPERTIES: - return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3, - s->handle, data[0], data[1]); - case CX2341X_ENC_SET_GOP_CLOSURE: - return 0; - case CX2341X_ENC_SET_AUDIO_PROPERTIES: - return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2, - s->handle, data[0]); - case CX2341X_ENC_MUTE_AUDIO: - return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2, - s->handle, data[0]); - case CX2341X_ENC_SET_BIT_RATE: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5, - s->handle, data[0], data[1], data[2], data[3]); - case CX2341X_ENC_MUTE_VIDEO: - return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, - s->handle, data[0]); - case CX2341X_ENC_SET_FRAME_DROP_RATE: - return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2, - s->handle, data[0]); - case CX2341X_ENC_MISC: - return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4, - s->handle, data[0], data[1], data[2]); - case CX2341X_ENC_SET_DNR_FILTER_MODE: - cx->filter_mode = (data[0] & 3) | (data[1] << 2); - return cx18_set_filter_param(s); - case CX2341X_ENC_SET_DNR_FILTER_PROPS: - cx->spatial_strength = data[0]; - cx->temporal_strength = data[1]; - return cx18_set_filter_param(s); - case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE: - return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3, - s->handle, data[0], data[1]); - case CX2341X_ENC_SET_CORING_LEVELS: - return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5, - s->handle, data[0], data[1], data[2], data[3]); - } - CX18_WARN("Unknown cmd %x\n", cmd); - return 0; -} - -int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], - u32 cmd, int args, ...) -{ - va_list ap; - int i; - - va_start(ap, args); - for (i = 0; i < args; i++) - data[i] = va_arg(ap, u32); - va_end(ap); - return cx18_api(cx, cmd, args, data); -} - -int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...) -{ - u32 data[MAX_MB_ARGUMENTS]; - va_list ap; - int i; - - if (cx == NULL) { - CX18_ERR("cx == NULL (cmd=%x)\n", cmd); - return 0; - } - if (args > MAX_MB_ARGUMENTS) { - CX18_ERR("args too big (cmd=%x)\n", cmd); - args = MAX_MB_ARGUMENTS; - } - va_start(ap, args); - for (i = 0; i < args; i++) - data[i] = va_arg(ap, u32); - va_end(ap); - return cx18_api(cx, cmd, args, data); -} diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h deleted file mode 100644 index b63fdfaac49..00000000000 --- a/drivers/media/video/cx18/cx18-mailbox.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * cx18 mailbox functions - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#ifndef _CX18_MAILBOX_H_ -#define _CX18_MAILBOX_H_ - -/* mailbox max args */ -#define MAX_MB_ARGUMENTS 6 -/* compatibility, should be same as the define in cx2341x.h */ -#define CX2341X_MBOX_MAX_DATA 16 - -#define MB_RESERVED_HANDLE_0 0 -#define MB_RESERVED_HANDLE_1 0xFFFFFFFF - -#define APU 0 -#define CPU 1 -#define EPU 2 -#define HPU 3 - -struct cx18; - -/* - * This structure is used by CPU to provide completed MDL & buffers information. - * Its structure is dictated by the layout of the SCB, required by the - * firmware, but its definition needs to be here, instead of in cx18-scb.h, - * for mailbox work order scheduling - */ -struct cx18_mdl_ack { - u32 id; /* ID of a completed MDL */ - u32 data_used; /* Total data filled in the MDL with 'id' */ -}; - -/* The cx18_mailbox struct is the mailbox structure which is used for passing - messages between processors */ -struct cx18_mailbox { - /* The sender sets a handle in 'request' after he fills the command. The - 'request' should be different than 'ack'. The sender, also, generates - an interrupt on XPU2YPU_irq where XPU is the sender and YPU is the - receiver. */ - u32 request; - /* The receiver detects a new command when 'req' is different than 'ack'. - He sets 'ack' to the same value as 'req' to clear the command. He, also, - generates an interrupt on YPU2XPU_irq where XPU is the sender and YPU - is the receiver. */ - u32 ack; - u32 reserved[6]; - /* 'cmd' identifies the command. The list of these commands are in - cx23418.h */ - u32 cmd; - /* Each command can have up to 6 arguments */ - u32 args[MAX_MB_ARGUMENTS]; - /* The return code can be one of the codes in the file cx23418.h. If the - command is completed successfully, the error will be ERR_SYS_SUCCESS. - If it is pending, the code is ERR_SYS_PENDING. If it failed, the error - code would indicate the task from which the error originated and will - be one of the errors in cx23418.h. In that case, the following - applies ((error & 0xff) != 0). - If the command is pending, the return will be passed in a MB from the - receiver to the sender. 'req' will be returned in args[0] */ - u32 error; -}; - -struct cx18_stream; - -int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]); -int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd, - int args, ...); -int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...); -int cx18_api_func(void *priv, u32 cmd, int in, int out, - u32 data[CX2341X_MBOX_MAX_DATA]); - -void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu); - -void cx18_in_work_handler(struct work_struct *work); - -#endif diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c deleted file mode 100644 index 8884537bd62..00000000000 --- a/drivers/media/video/cx18/cx18-queue.c +++ /dev/null @@ -1,443 +0,0 @@ -/* - * cx18 buffer queues - * - * Derived from ivtv-queue.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-queue.h" -#include "cx18-streams.h" -#include "cx18-scb.h" -#include "cx18-io.h" - -void cx18_buf_swap(struct cx18_buffer *buf) -{ - int i; - - for (i = 0; i < buf->bytesused; i += 4) - swab32s((u32 *)(buf->buf + i)); -} - -void _cx18_mdl_swap(struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - - list_for_each_entry(buf, &mdl->buf_list, list) { - if (buf->bytesused == 0) - break; - cx18_buf_swap(buf); - } -} - -void cx18_queue_init(struct cx18_queue *q) -{ - INIT_LIST_HEAD(&q->list); - atomic_set(&q->depth, 0); - q->bytesused = 0; -} - -struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, - struct cx18_queue *q, int to_front) -{ - /* clear the mdl if it is not to be enqueued to the full queue */ - if (q != &s->q_full) { - mdl->bytesused = 0; - mdl->readpos = 0; - mdl->m_flags = 0; - mdl->skipped = 0; - mdl->curr_buf = NULL; - } - - /* q_busy is restricted to a max buffer count imposed by firmware */ - if (q == &s->q_busy && - atomic_read(&q->depth) >= CX18_MAX_FW_MDLS_PER_STREAM) - q = &s->q_free; - - spin_lock(&q->lock); - - if (to_front) - list_add(&mdl->list, &q->list); /* LIFO */ - else - list_add_tail(&mdl->list, &q->list); /* FIFO */ - q->bytesused += mdl->bytesused - mdl->readpos; - atomic_inc(&q->depth); - - spin_unlock(&q->lock); - return q; -} - -struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) -{ - struct cx18_mdl *mdl = NULL; - - spin_lock(&q->lock); - if (!list_empty(&q->list)) { - mdl = list_first_entry(&q->list, struct cx18_mdl, list); - list_del_init(&mdl->list); - q->bytesused -= mdl->bytesused - mdl->readpos; - mdl->skipped = 0; - atomic_dec(&q->depth); - } - spin_unlock(&q->lock); - return mdl; -} - -static void _cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - u32 buf_size = s->buf_size; - u32 bytesused = mdl->bytesused; - - list_for_each_entry(buf, &mdl->buf_list, list) { - buf->readpos = 0; - if (bytesused >= buf_size) { - buf->bytesused = buf_size; - bytesused -= buf_size; - } else { - buf->bytesused = bytesused; - bytesused = 0; - } - cx18_buf_sync_for_cpu(s, buf); - } -} - -static inline void cx18_mdl_update_bufs_for_cpu(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - struct cx18_buffer *buf; - - if (list_is_singular(&mdl->buf_list)) { - buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, - list); - buf->bytesused = mdl->bytesused; - buf->readpos = 0; - cx18_buf_sync_for_cpu(s, buf); - } else { - _cx18_mdl_update_bufs_for_cpu(s, mdl); - } -} - -struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id, - u32 bytesused) -{ - struct cx18 *cx = s->cx; - struct cx18_mdl *mdl; - struct cx18_mdl *tmp; - struct cx18_mdl *ret = NULL; - LIST_HEAD(sweep_up); - - /* - * We don't have to acquire multiple q locks here, because we are - * serialized by the single threaded work handler. - * MDLs from the firmware will thus remain in order as - * they are moved from q_busy to q_full or to the dvb ring buffer. - */ - spin_lock(&s->q_busy.lock); - list_for_each_entry_safe(mdl, tmp, &s->q_busy.list, list) { - /* - * We should find what the firmware told us is done, - * right at the front of the queue. If we don't, we likely have - * missed an mdl done message from the firmware. - * Once we skip an mdl repeatedly, relative to the size of - * q_busy, we have high confidence we've missed it. - */ - if (mdl->id != id) { - mdl->skipped++; - if (mdl->skipped >= atomic_read(&s->q_busy.depth)-1) { - /* mdl must have fallen out of rotation */ - CX18_WARN("Skipped %s, MDL %d, %d " - "times - it must have dropped out of " - "rotation\n", s->name, mdl->id, - mdl->skipped); - /* Sweep it up to put it back into rotation */ - list_move_tail(&mdl->list, &sweep_up); - atomic_dec(&s->q_busy.depth); - } - continue; - } - /* - * We pull the desired mdl off of the queue here. Something - * will have to put it back on a queue later. - */ - list_del_init(&mdl->list); - atomic_dec(&s->q_busy.depth); - ret = mdl; - break; - } - spin_unlock(&s->q_busy.lock); - - /* - * We found the mdl for which we were looking. Get it ready for - * the caller to put on q_full or in the dvb ring buffer. - */ - if (ret != NULL) { - ret->bytesused = bytesused; - ret->skipped = 0; - /* 0'ed readpos, m_flags & curr_buf when mdl went on q_busy */ - cx18_mdl_update_bufs_for_cpu(s, ret); - if (s->type != CX18_ENC_STREAM_TYPE_TS) - set_bit(CX18_F_M_NEED_SWAP, &ret->m_flags); - } - - /* Put any mdls the firmware is ignoring back into normal rotation */ - list_for_each_entry_safe(mdl, tmp, &sweep_up, list) { - list_del_init(&mdl->list); - cx18_enqueue(s, mdl, &s->q_free); - } - return ret; -} - -/* Move all mdls of a queue, while flushing the mdl */ -static void cx18_queue_flush(struct cx18_stream *s, - struct cx18_queue *q_src, struct cx18_queue *q_dst) -{ - struct cx18_mdl *mdl; - - /* It only makes sense to flush to q_free or q_idle */ - if (q_src == q_dst || q_dst == &s->q_full || q_dst == &s->q_busy) - return; - - spin_lock(&q_src->lock); - spin_lock(&q_dst->lock); - while (!list_empty(&q_src->list)) { - mdl = list_first_entry(&q_src->list, struct cx18_mdl, list); - list_move_tail(&mdl->list, &q_dst->list); - mdl->bytesused = 0; - mdl->readpos = 0; - mdl->m_flags = 0; - mdl->skipped = 0; - mdl->curr_buf = NULL; - atomic_inc(&q_dst->depth); - } - cx18_queue_init(q_src); - spin_unlock(&q_src->lock); - spin_unlock(&q_dst->lock); -} - -void cx18_flush_queues(struct cx18_stream *s) -{ - cx18_queue_flush(s, &s->q_busy, &s->q_free); - cx18_queue_flush(s, &s->q_full, &s->q_free); -} - -/* - * Note, s->buf_pool is not protected by a lock, - * the stream better not have *anything* going on when calling this - */ -void cx18_unload_queues(struct cx18_stream *s) -{ - struct cx18_queue *q_idle = &s->q_idle; - struct cx18_mdl *mdl; - struct cx18_buffer *buf; - - /* Move all MDLS to q_idle */ - cx18_queue_flush(s, &s->q_busy, q_idle); - cx18_queue_flush(s, &s->q_full, q_idle); - cx18_queue_flush(s, &s->q_free, q_idle); - - /* Reset MDL id's and move all buffers back to the stream's buf_pool */ - spin_lock(&q_idle->lock); - list_for_each_entry(mdl, &q_idle->list, list) { - while (!list_empty(&mdl->buf_list)) { - buf = list_first_entry(&mdl->buf_list, - struct cx18_buffer, list); - list_move_tail(&buf->list, &s->buf_pool); - buf->bytesused = 0; - buf->readpos = 0; - } - mdl->id = s->mdl_base_idx; /* reset id to a "safe" value */ - /* all other mdl fields were cleared by cx18_queue_flush() */ - } - spin_unlock(&q_idle->lock); -} - -/* - * Note, s->buf_pool is not protected by a lock, - * the stream better not have *anything* going on when calling this - */ -void cx18_load_queues(struct cx18_stream *s) -{ - struct cx18 *cx = s->cx; - struct cx18_mdl *mdl; - struct cx18_buffer *buf; - int mdl_id; - int i; - u32 partial_buf_size; - - /* - * Attach buffers to MDLs, give the MDLs ids, and add MDLs to q_free - * Excess MDLs are left on q_idle - * Excess buffers are left in buf_pool and/or on an MDL in q_idle - */ - mdl_id = s->mdl_base_idx; - for (mdl = cx18_dequeue(s, &s->q_idle), i = s->bufs_per_mdl; - mdl != NULL && i == s->bufs_per_mdl; - mdl = cx18_dequeue(s, &s->q_idle)) { - - mdl->id = mdl_id; - - for (i = 0; i < s->bufs_per_mdl; i++) { - if (list_empty(&s->buf_pool)) - break; - - buf = list_first_entry(&s->buf_pool, struct cx18_buffer, - list); - list_move_tail(&buf->list, &mdl->buf_list); - - /* update the firmware's MDL array with this buffer */ - cx18_writel(cx, buf->dma_handle, - &cx->scb->cpu_mdl[mdl_id + i].paddr); - cx18_writel(cx, s->buf_size, - &cx->scb->cpu_mdl[mdl_id + i].length); - } - - if (i == s->bufs_per_mdl) { - /* - * The encoder doesn't honor s->mdl_size. So in the - * case of a non-integral number of buffers to meet - * mdl_size, we lie about the size of the last buffer - * in the MDL to get the encoder to really only send - * us mdl_size bytes per MDL transfer. - */ - partial_buf_size = s->mdl_size % s->buf_size; - if (partial_buf_size) { - cx18_writel(cx, partial_buf_size, - &cx->scb->cpu_mdl[mdl_id + i - 1].length); - } - cx18_enqueue(s, mdl, &s->q_free); - } else { - /* Not enough buffers for this MDL; we won't use it */ - cx18_push(s, mdl, &s->q_idle); - } - mdl_id += i; - } -} - -void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl) -{ - int dma = s->dma; - u32 buf_size = s->buf_size; - struct pci_dev *pci_dev = s->cx->pci_dev; - struct cx18_buffer *buf; - - list_for_each_entry(buf, &mdl->buf_list, list) - pci_dma_sync_single_for_device(pci_dev, buf->dma_handle, - buf_size, dma); -} - -int cx18_stream_alloc(struct cx18_stream *s) -{ - struct cx18 *cx = s->cx; - int i; - - if (s->buffers == 0) - return 0; - - CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers " - "(%d.%02d kB total)\n", - s->name, s->buffers, s->buf_size, - s->buffers * s->buf_size / 1024, - (s->buffers * s->buf_size * 100 / 1024) % 100); - - if (((char __iomem *)&cx->scb->cpu_mdl[cx->free_mdl_idx + s->buffers] - - (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) { - unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE - - ((char __iomem *)cx->scb->cpu_mdl)); - - CX18_ERR("Too many buffers, cannot fit in SCB area\n"); - CX18_ERR("Max buffers = %zd\n", - bufsz / sizeof(struct cx18_mdl_ent)); - return -ENOMEM; - } - - s->mdl_base_idx = cx->free_mdl_idx; - - /* allocate stream buffers and MDLs */ - for (i = 0; i < s->buffers; i++) { - struct cx18_mdl *mdl; - struct cx18_buffer *buf; - - /* 1 MDL per buffer to handle the worst & also default case */ - mdl = kzalloc(sizeof(struct cx18_mdl), GFP_KERNEL|__GFP_NOWARN); - if (mdl == NULL) - break; - - buf = kzalloc(sizeof(struct cx18_buffer), - GFP_KERNEL|__GFP_NOWARN); - if (buf == NULL) { - kfree(mdl); - break; - } - - buf->buf = kmalloc(s->buf_size, GFP_KERNEL|__GFP_NOWARN); - if (buf->buf == NULL) { - kfree(mdl); - kfree(buf); - break; - } - - INIT_LIST_HEAD(&mdl->list); - INIT_LIST_HEAD(&mdl->buf_list); - mdl->id = s->mdl_base_idx; /* a somewhat safe value */ - cx18_enqueue(s, mdl, &s->q_idle); - - INIT_LIST_HEAD(&buf->list); - buf->dma_handle = pci_map_single(s->cx->pci_dev, - buf->buf, s->buf_size, s->dma); - cx18_buf_sync_for_cpu(s, buf); - list_add_tail(&buf->list, &s->buf_pool); - } - if (i == s->buffers) { - cx->free_mdl_idx += s->buffers; - return 0; - } - CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name); - cx18_stream_free(s); - return -ENOMEM; -} - -void cx18_stream_free(struct cx18_stream *s) -{ - struct cx18_mdl *mdl; - struct cx18_buffer *buf; - struct cx18 *cx = s->cx; - - CX18_DEBUG_INFO("Deallocating buffers for %s stream\n", s->name); - - /* move all buffers to buf_pool and all MDLs to q_idle */ - cx18_unload_queues(s); - - /* empty q_idle */ - while ((mdl = cx18_dequeue(s, &s->q_idle))) - kfree(mdl); - - /* empty buf_pool */ - while (!list_empty(&s->buf_pool)) { - buf = list_first_entry(&s->buf_pool, struct cx18_buffer, list); - list_del_init(&buf->list); - - pci_unmap_single(s->cx->pci_dev, buf->dma_handle, - s->buf_size, s->dma); - kfree(buf->buf); - kfree(buf); - } -} diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h deleted file mode 100644 index 4201ddc1609..00000000000 --- a/drivers/media/video/cx18/cx18-queue.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * cx18 buffer queues - * - * Derived from ivtv-queue.h - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#define CX18_DMA_UNMAPPED ((u32) -1) - -/* cx18_buffer utility functions */ - -static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s, - struct cx18_buffer *buf) -{ - pci_dma_sync_single_for_cpu(s->cx->pci_dev, buf->dma_handle, - s->buf_size, s->dma); -} - -static inline void cx18_buf_sync_for_device(struct cx18_stream *s, - struct cx18_buffer *buf) -{ - pci_dma_sync_single_for_device(s->cx->pci_dev, buf->dma_handle, - s->buf_size, s->dma); -} - -void _cx18_mdl_sync_for_device(struct cx18_stream *s, struct cx18_mdl *mdl); - -static inline void cx18_mdl_sync_for_device(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - if (list_is_singular(&mdl->buf_list)) - cx18_buf_sync_for_device(s, list_first_entry(&mdl->buf_list, - struct cx18_buffer, - list)); - else - _cx18_mdl_sync_for_device(s, mdl); -} - -void cx18_buf_swap(struct cx18_buffer *buf); -void _cx18_mdl_swap(struct cx18_mdl *mdl); - -static inline void cx18_mdl_swap(struct cx18_mdl *mdl) -{ - if (list_is_singular(&mdl->buf_list)) - cx18_buf_swap(list_first_entry(&mdl->buf_list, - struct cx18_buffer, list)); - else - _cx18_mdl_swap(mdl); -} - -/* cx18_queue utility functions */ -struct cx18_queue *_cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, - struct cx18_queue *q, int to_front); - -static inline -struct cx18_queue *cx18_enqueue(struct cx18_stream *s, struct cx18_mdl *mdl, - struct cx18_queue *q) -{ - return _cx18_enqueue(s, mdl, q, 0); /* FIFO */ -} - -static inline -struct cx18_queue *cx18_push(struct cx18_stream *s, struct cx18_mdl *mdl, - struct cx18_queue *q) -{ - return _cx18_enqueue(s, mdl, q, 1); /* LIFO */ -} - -void cx18_queue_init(struct cx18_queue *q); -struct cx18_mdl *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); -struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id, - u32 bytesused); -void cx18_flush_queues(struct cx18_stream *s); - -/* queue MDL reconfiguration helpers */ -void cx18_unload_queues(struct cx18_stream *s); -void cx18_load_queues(struct cx18_stream *s); - -/* cx18_stream utility functions */ -int cx18_stream_alloc(struct cx18_stream *s); -void cx18_stream_free(struct cx18_stream *s); diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c deleted file mode 100644 index 85cc59637e5..00000000000 --- a/drivers/media/video/cx18/cx18-scb.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * cx18 System Control Block initialization - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-scb.h" - -void cx18_init_scb(struct cx18 *cx) -{ - cx18_setup_page(cx, SCB_OFFSET); - cx18_memset_io(cx, cx->scb, 0, 0x10000); - - cx18_writel(cx, IRQ_APU_TO_CPU, &cx->scb->apu2cpu_irq); - cx18_writel(cx, IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack); - cx18_writel(cx, IRQ_HPU_TO_CPU, &cx->scb->hpu2cpu_irq); - cx18_writel(cx, IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack); - cx18_writel(cx, IRQ_PPU_TO_CPU, &cx->scb->ppu2cpu_irq); - cx18_writel(cx, IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack); - cx18_writel(cx, IRQ_EPU_TO_CPU, &cx->scb->epu2cpu_irq); - cx18_writel(cx, IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack); - - cx18_writel(cx, IRQ_CPU_TO_APU, &cx->scb->cpu2apu_irq); - cx18_writel(cx, IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack); - cx18_writel(cx, IRQ_HPU_TO_APU, &cx->scb->hpu2apu_irq); - cx18_writel(cx, IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack); - cx18_writel(cx, IRQ_PPU_TO_APU, &cx->scb->ppu2apu_irq); - cx18_writel(cx, IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack); - cx18_writel(cx, IRQ_EPU_TO_APU, &cx->scb->epu2apu_irq); - cx18_writel(cx, IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack); - - cx18_writel(cx, IRQ_CPU_TO_HPU, &cx->scb->cpu2hpu_irq); - cx18_writel(cx, IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack); - cx18_writel(cx, IRQ_APU_TO_HPU, &cx->scb->apu2hpu_irq); - cx18_writel(cx, IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack); - cx18_writel(cx, IRQ_PPU_TO_HPU, &cx->scb->ppu2hpu_irq); - cx18_writel(cx, IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack); - cx18_writel(cx, IRQ_EPU_TO_HPU, &cx->scb->epu2hpu_irq); - cx18_writel(cx, IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack); - - cx18_writel(cx, IRQ_CPU_TO_PPU, &cx->scb->cpu2ppu_irq); - cx18_writel(cx, IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack); - cx18_writel(cx, IRQ_APU_TO_PPU, &cx->scb->apu2ppu_irq); - cx18_writel(cx, IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack); - cx18_writel(cx, IRQ_HPU_TO_PPU, &cx->scb->hpu2ppu_irq); - cx18_writel(cx, IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack); - cx18_writel(cx, IRQ_EPU_TO_PPU, &cx->scb->epu2ppu_irq); - cx18_writel(cx, IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack); - - cx18_writel(cx, IRQ_CPU_TO_EPU, &cx->scb->cpu2epu_irq); - cx18_writel(cx, IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack); - cx18_writel(cx, IRQ_APU_TO_EPU, &cx->scb->apu2epu_irq); - cx18_writel(cx, IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack); - cx18_writel(cx, IRQ_HPU_TO_EPU, &cx->scb->hpu2epu_irq); - cx18_writel(cx, IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack); - cx18_writel(cx, IRQ_PPU_TO_EPU, &cx->scb->ppu2epu_irq); - cx18_writel(cx, IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack); - - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb), - &cx->scb->apu2cpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb), - &cx->scb->hpu2cpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb), - &cx->scb->ppu2cpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb), - &cx->scb->epu2cpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb), - &cx->scb->cpu2apu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb), - &cx->scb->hpu2apu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb), - &cx->scb->ppu2apu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb), - &cx->scb->epu2apu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb), - &cx->scb->cpu2hpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb), - &cx->scb->apu2hpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb), - &cx->scb->ppu2hpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb), - &cx->scb->epu2hpu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb), - &cx->scb->cpu2ppu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb), - &cx->scb->apu2ppu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb), - &cx->scb->hpu2ppu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb), - &cx->scb->epu2ppu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb), - &cx->scb->cpu2epu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb), - &cx->scb->apu2epu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb), - &cx->scb->hpu2epu_mb_offset); - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb), - &cx->scb->ppu2epu_mb_offset); - - cx18_writel(cx, SCB_OFFSET + offsetof(struct cx18_scb, cpu_state), - &cx->scb->ipc_offset); - - cx18_writel(cx, 1, &cx->scb->epu_state); -} diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h deleted file mode 100644 index 08877652e32..00000000000 --- a/drivers/media/video/cx18/cx18-scb.h +++ /dev/null @@ -1,280 +0,0 @@ -/* - * cx18 System Control Block initialization - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#ifndef CX18_SCB_H -#define CX18_SCB_H - -#include "cx18-mailbox.h" - -/* NOTE: All ACK interrupts are in the SW2 register. All non-ACK interrupts - are in the SW1 register. */ - -#define IRQ_APU_TO_CPU 0x00000001 -#define IRQ_CPU_TO_APU_ACK 0x00000001 -#define IRQ_HPU_TO_CPU 0x00000002 -#define IRQ_CPU_TO_HPU_ACK 0x00000002 -#define IRQ_PPU_TO_CPU 0x00000004 -#define IRQ_CPU_TO_PPU_ACK 0x00000004 -#define IRQ_EPU_TO_CPU 0x00000008 -#define IRQ_CPU_TO_EPU_ACK 0x00000008 - -#define IRQ_CPU_TO_APU 0x00000010 -#define IRQ_APU_TO_CPU_ACK 0x00000010 -#define IRQ_HPU_TO_APU 0x00000020 -#define IRQ_APU_TO_HPU_ACK 0x00000020 -#define IRQ_PPU_TO_APU 0x00000040 -#define IRQ_APU_TO_PPU_ACK 0x00000040 -#define IRQ_EPU_TO_APU 0x00000080 -#define IRQ_APU_TO_EPU_ACK 0x00000080 - -#define IRQ_CPU_TO_HPU 0x00000100 -#define IRQ_HPU_TO_CPU_ACK 0x00000100 -#define IRQ_APU_TO_HPU 0x00000200 -#define IRQ_HPU_TO_APU_ACK 0x00000200 -#define IRQ_PPU_TO_HPU 0x00000400 -#define IRQ_HPU_TO_PPU_ACK 0x00000400 -#define IRQ_EPU_TO_HPU 0x00000800 -#define IRQ_HPU_TO_EPU_ACK 0x00000800 - -#define IRQ_CPU_TO_PPU 0x00001000 -#define IRQ_PPU_TO_CPU_ACK 0x00001000 -#define IRQ_APU_TO_PPU 0x00002000 -#define IRQ_PPU_TO_APU_ACK 0x00002000 -#define IRQ_HPU_TO_PPU 0x00004000 -#define IRQ_PPU_TO_HPU_ACK 0x00004000 -#define IRQ_EPU_TO_PPU 0x00008000 -#define IRQ_PPU_TO_EPU_ACK 0x00008000 - -#define IRQ_CPU_TO_EPU 0x00010000 -#define IRQ_EPU_TO_CPU_ACK 0x00010000 -#define IRQ_APU_TO_EPU 0x00020000 -#define IRQ_EPU_TO_APU_ACK 0x00020000 -#define IRQ_HPU_TO_EPU 0x00040000 -#define IRQ_EPU_TO_HPU_ACK 0x00040000 -#define IRQ_PPU_TO_EPU 0x00080000 -#define IRQ_EPU_TO_PPU_ACK 0x00080000 - -#define SCB_OFFSET 0xDC0000 - -/* If Firmware uses fixed memory map, it shall not allocate the area - between SCB_OFFSET and SCB_OFFSET+SCB_RESERVED_SIZE-1 inclusive */ -#define SCB_RESERVED_SIZE 0x10000 - - -/* This structure is used by EPU to provide memory descriptors in its memory */ -struct cx18_mdl_ent { - u32 paddr; /* Physical address of a buffer segment */ - u32 length; /* Length of the buffer segment */ -}; - -struct cx18_scb { - /* These fields form the System Control Block which is used at boot time - for localizing the IPC data as well as the code positions for all - processors. The offsets are from the start of this struct. */ - - /* Offset where to find the Inter-Processor Communication data */ - u32 ipc_offset; - u32 reserved01[7]; - /* Offset where to find the start of the CPU code */ - u32 cpu_code_offset; - u32 reserved02[3]; - /* Offset where to find the start of the APU code */ - u32 apu_code_offset; - u32 reserved03[3]; - /* Offset where to find the start of the HPU code */ - u32 hpu_code_offset; - u32 reserved04[3]; - /* Offset where to find the start of the PPU code */ - u32 ppu_code_offset; - u32 reserved05[3]; - - /* These fields form Inter-Processor Communication data which is used - by all processors to locate the information needed for communicating - with other processors */ - - /* Fields for CPU: */ - - /* bit 0: 1/0 processor ready/not ready. Set other bits to 0. */ - u32 cpu_state; - u32 reserved1[7]; - /* Offset to the mailbox used for sending commands from APU to CPU */ - u32 apu2cpu_mb_offset; - /* Value to write to register SW1 register set (0xC7003100) after the - command is ready */ - u32 apu2cpu_irq; - /* Value to write to register SW2 register set (0xC7003140) after the - command is cleared */ - u32 cpu2apu_irq_ack; - u32 reserved2[13]; - - u32 hpu2cpu_mb_offset; - u32 hpu2cpu_irq; - u32 cpu2hpu_irq_ack; - u32 reserved3[13]; - - u32 ppu2cpu_mb_offset; - u32 ppu2cpu_irq; - u32 cpu2ppu_irq_ack; - u32 reserved4[13]; - - u32 epu2cpu_mb_offset; - u32 epu2cpu_irq; - u32 cpu2epu_irq_ack; - u32 reserved5[13]; - u32 reserved6[8]; - - /* Fields for APU: */ - - u32 apu_state; - u32 reserved11[7]; - u32 cpu2apu_mb_offset; - u32 cpu2apu_irq; - u32 apu2cpu_irq_ack; - u32 reserved12[13]; - - u32 hpu2apu_mb_offset; - u32 hpu2apu_irq; - u32 apu2hpu_irq_ack; - u32 reserved13[13]; - - u32 ppu2apu_mb_offset; - u32 ppu2apu_irq; - u32 apu2ppu_irq_ack; - u32 reserved14[13]; - - u32 epu2apu_mb_offset; - u32 epu2apu_irq; - u32 apu2epu_irq_ack; - u32 reserved15[13]; - u32 reserved16[8]; - - /* Fields for HPU: */ - - u32 hpu_state; - u32 reserved21[7]; - u32 cpu2hpu_mb_offset; - u32 cpu2hpu_irq; - u32 hpu2cpu_irq_ack; - u32 reserved22[13]; - - u32 apu2hpu_mb_offset; - u32 apu2hpu_irq; - u32 hpu2apu_irq_ack; - u32 reserved23[13]; - - u32 ppu2hpu_mb_offset; - u32 ppu2hpu_irq; - u32 hpu2ppu_irq_ack; - u32 reserved24[13]; - - u32 epu2hpu_mb_offset; - u32 epu2hpu_irq; - u32 hpu2epu_irq_ack; - u32 reserved25[13]; - u32 reserved26[8]; - - /* Fields for PPU: */ - - u32 ppu_state; - u32 reserved31[7]; - u32 cpu2ppu_mb_offset; - u32 cpu2ppu_irq; - u32 ppu2cpu_irq_ack; - u32 reserved32[13]; - - u32 apu2ppu_mb_offset; - u32 apu2ppu_irq; - u32 ppu2apu_irq_ack; - u32 reserved33[13]; - - u32 hpu2ppu_mb_offset; - u32 hpu2ppu_irq; - u32 ppu2hpu_irq_ack; - u32 reserved34[13]; - - u32 epu2ppu_mb_offset; - u32 epu2ppu_irq; - u32 ppu2epu_irq_ack; - u32 reserved35[13]; - u32 reserved36[8]; - - /* Fields for EPU: */ - - u32 epu_state; - u32 reserved41[7]; - u32 cpu2epu_mb_offset; - u32 cpu2epu_irq; - u32 epu2cpu_irq_ack; - u32 reserved42[13]; - - u32 apu2epu_mb_offset; - u32 apu2epu_irq; - u32 epu2apu_irq_ack; - u32 reserved43[13]; - - u32 hpu2epu_mb_offset; - u32 hpu2epu_irq; - u32 epu2hpu_irq_ack; - u32 reserved44[13]; - - u32 ppu2epu_mb_offset; - u32 ppu2epu_irq; - u32 epu2ppu_irq_ack; - u32 reserved45[13]; - u32 reserved46[8]; - - u32 semaphores[8]; /* Semaphores */ - - u32 reserved50[32]; /* Reserved for future use */ - - struct cx18_mailbox apu2cpu_mb; - struct cx18_mailbox hpu2cpu_mb; - struct cx18_mailbox ppu2cpu_mb; - struct cx18_mailbox epu2cpu_mb; - - struct cx18_mailbox cpu2apu_mb; - struct cx18_mailbox hpu2apu_mb; - struct cx18_mailbox ppu2apu_mb; - struct cx18_mailbox epu2apu_mb; - - struct cx18_mailbox cpu2hpu_mb; - struct cx18_mailbox apu2hpu_mb; - struct cx18_mailbox ppu2hpu_mb; - struct cx18_mailbox epu2hpu_mb; - - struct cx18_mailbox cpu2ppu_mb; - struct cx18_mailbox apu2ppu_mb; - struct cx18_mailbox hpu2ppu_mb; - struct cx18_mailbox epu2ppu_mb; - - struct cx18_mailbox cpu2epu_mb; - struct cx18_mailbox apu2epu_mb; - struct cx18_mailbox hpu2epu_mb; - struct cx18_mailbox ppu2epu_mb; - - struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS]; - struct cx18_mdl_ent cpu_mdl[1]; -}; - -void cx18_init_scb(struct cx18 *cx); - -#endif diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c deleted file mode 100644 index 9d598ab8861..00000000000 --- a/drivers/media/video/cx18/cx18-streams.c +++ /dev/null @@ -1,1060 +0,0 @@ -/* - * cx18 init/start/stop/exit stream functions - * - * Derived from ivtv-streams.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-io.h" -#include "cx18-fileops.h" -#include "cx18-mailbox.h" -#include "cx18-i2c.h" -#include "cx18-queue.h" -#include "cx18-ioctl.h" -#include "cx18-streams.h" -#include "cx18-cards.h" -#include "cx18-scb.h" -#include "cx18-dvb.h" - -#define CX18_DSP0_INTERRUPT_MASK 0xd0004C - -static struct v4l2_file_operations cx18_v4l2_enc_fops = { - .owner = THIS_MODULE, - .read = cx18_v4l2_read, - .open = cx18_v4l2_open, - .unlocked_ioctl = video_ioctl2, - .release = cx18_v4l2_close, - .poll = cx18_v4l2_enc_poll, - .mmap = cx18_v4l2_mmap, -}; - -/* offset from 0 to register ts v4l2 minors on */ -#define CX18_V4L2_ENC_TS_OFFSET 16 -/* offset from 0 to register pcm v4l2 minors on */ -#define CX18_V4L2_ENC_PCM_OFFSET 24 -/* offset from 0 to register yuv v4l2 minors on */ -#define CX18_V4L2_ENC_YUV_OFFSET 32 - -static struct { - const char *name; - int vfl_type; - int num_offset; - int dma; - enum v4l2_buf_type buf_type; -} cx18_stream_info[] = { - { /* CX18_ENC_STREAM_TYPE_MPG */ - "encoder MPEG", - VFL_TYPE_GRABBER, 0, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, - }, - { /* CX18_ENC_STREAM_TYPE_TS */ - "TS", - VFL_TYPE_GRABBER, -1, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, - }, - { /* CX18_ENC_STREAM_TYPE_YUV */ - "encoder YUV", - VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, - }, - { /* CX18_ENC_STREAM_TYPE_VBI */ - "encoder VBI", - VFL_TYPE_VBI, 0, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE, - }, - { /* CX18_ENC_STREAM_TYPE_PCM */ - "encoder PCM audio", - VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE, - }, - { /* CX18_ENC_STREAM_TYPE_IDX */ - "encoder IDX", - VFL_TYPE_GRABBER, -1, - PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE, - }, - { /* CX18_ENC_STREAM_TYPE_RAD */ - "encoder radio", - VFL_TYPE_RADIO, 0, - PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE, - }, -}; - - -void cx18_dma_free(struct videobuf_queue *q, - struct cx18_stream *s, struct cx18_videobuf_buffer *buf) -{ - videobuf_waiton(q, &buf->vb, 0, 0); - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int cx18_prepare_buffer(struct videobuf_queue *q, - struct cx18_stream *s, - struct cx18_videobuf_buffer *buf, - u32 pixelformat, - unsigned int width, unsigned int height, - enum v4l2_field field) -{ - struct cx18 *cx = s->cx; - int rc = 0; - - /* check settings */ - buf->bytes_used = 0; - - if ((width < 48) || (height < 32)) - return -EINVAL; - - buf->vb.size = (width * height * 2); - if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) - return -EINVAL; - - /* alloc + fill struct (if changed) */ - if (buf->vb.width != width || buf->vb.height != height || - buf->vb.field != field || s->pixelformat != pixelformat || - buf->tvnorm != cx->std) { - - buf->vb.width = width; - buf->vb.height = height; - buf->vb.field = field; - buf->tvnorm = cx->std; - s->pixelformat = pixelformat; - - /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) - UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) - s->vb_bytes_per_frame = height * 720 * 3 / 2; - else - s->vb_bytes_per_frame = height * 720 * 2; - cx18_dma_free(q, s, buf); - } - - if ((buf->vb.baddr != 0) && (buf->vb.bsize < buf->vb.size)) - return -EINVAL; - - if (buf->vb.field == 0) - buf->vb.field = V4L2_FIELD_INTERLACED; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - buf->vb.width = width; - buf->vb.height = height; - buf->vb.field = field; - buf->tvnorm = cx->std; - s->pixelformat = pixelformat; - - /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) - UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) - s->vb_bytes_per_frame = height * 720 * 3 / 2; - else - s->vb_bytes_per_frame = height * 720 * 2; - rc = videobuf_iolock(q, &buf->vb, NULL); - if (rc != 0) - goto fail; - } - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - cx18_dma_free(q, s, buf); - return rc; - -} - -/* VB_MIN_BUFSIZE is lcm(1440 * 480, 1440 * 576) - 1440 is a single line of 4:2:2 YUV at 720 luma samples wide -*/ -#define VB_MIN_BUFFERS 32 -#define VB_MIN_BUFSIZE 4147200 - -static int buffer_setup(struct videobuf_queue *q, - unsigned int *count, unsigned int *size) -{ - struct cx18_stream *s = q->priv_data; - struct cx18 *cx = s->cx; - - *size = 2 * cx->cxhdl.width * cx->cxhdl.height; - if (*count == 0) - *count = VB_MIN_BUFFERS; - - while (*size * *count > VB_MIN_BUFFERS * VB_MIN_BUFSIZE) - (*count)--; - - q->field = V4L2_FIELD_INTERLACED; - q->last = V4L2_FIELD_INTERLACED; - - return 0; -} - -static int buffer_prepare(struct videobuf_queue *q, - struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct cx18_videobuf_buffer *buf = - container_of(vb, struct cx18_videobuf_buffer, vb); - struct cx18_stream *s = q->priv_data; - struct cx18 *cx = s->cx; - - return cx18_prepare_buffer(q, s, buf, s->pixelformat, - cx->cxhdl.width, cx->cxhdl.height, field); -} - -static void buffer_release(struct videobuf_queue *q, - struct videobuf_buffer *vb) -{ - struct cx18_videobuf_buffer *buf = - container_of(vb, struct cx18_videobuf_buffer, vb); - struct cx18_stream *s = q->priv_data; - - cx18_dma_free(q, s, buf); -} - -static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) -{ - struct cx18_videobuf_buffer *buf = - container_of(vb, struct cx18_videobuf_buffer, vb); - struct cx18_stream *s = q->priv_data; - - buf->vb.state = VIDEOBUF_QUEUED; - - list_add_tail(&buf->vb.queue, &s->vb_capture); -} - -static struct videobuf_queue_ops cx18_videobuf_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -static void cx18_stream_init(struct cx18 *cx, int type) -{ - struct cx18_stream *s = &cx->streams[type]; - struct video_device *video_dev = s->video_dev; - - /* we need to keep video_dev, so restore it afterwards */ - memset(s, 0, sizeof(*s)); - s->video_dev = video_dev; - - /* initialize cx18_stream fields */ - s->dvb = NULL; - s->cx = cx; - s->type = type; - s->name = cx18_stream_info[type].name; - s->handle = CX18_INVALID_TASK_HANDLE; - - s->dma = cx18_stream_info[type].dma; - s->buffers = cx->stream_buffers[type]; - s->buf_size = cx->stream_buf_size[type]; - INIT_LIST_HEAD(&s->buf_pool); - s->bufs_per_mdl = 1; - s->mdl_size = s->buf_size * s->bufs_per_mdl; - - init_waitqueue_head(&s->waitq); - s->id = -1; - spin_lock_init(&s->q_free.lock); - cx18_queue_init(&s->q_free); - spin_lock_init(&s->q_busy.lock); - cx18_queue_init(&s->q_busy); - spin_lock_init(&s->q_full.lock); - cx18_queue_init(&s->q_full); - spin_lock_init(&s->q_idle.lock); - cx18_queue_init(&s->q_idle); - - INIT_WORK(&s->out_work_order, cx18_out_work_handler); - - INIT_LIST_HEAD(&s->vb_capture); - s->vb_timeout.function = cx18_vb_timeout; - s->vb_timeout.data = (unsigned long)s; - init_timer(&s->vb_timeout); - spin_lock_init(&s->vb_lock); - if (type == CX18_ENC_STREAM_TYPE_YUV) { - spin_lock_init(&s->vbuf_q_lock); - - s->vb_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - videobuf_queue_vmalloc_init(&s->vbuf_q, &cx18_videobuf_qops, - &cx->pci_dev->dev, &s->vbuf_q_lock, - V4L2_BUF_TYPE_VIDEO_CAPTURE, - V4L2_FIELD_INTERLACED, - sizeof(struct cx18_videobuf_buffer), - s, &cx->serialize_lock); - - /* Assume the previous pixel default */ - s->pixelformat = V4L2_PIX_FMT_HM12; - s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2; - } -} - -static int cx18_prep_dev(struct cx18 *cx, int type) -{ - struct cx18_stream *s = &cx->streams[type]; - u32 cap = cx->v4l2_cap; - int num_offset = cx18_stream_info[type].num_offset; - int num = cx->instance + cx18_first_minor + num_offset; - - /* - * These five fields are always initialized. - * For analog capture related streams, if video_dev == NULL then the - * stream is not in use. - * For the TS stream, if dvb == NULL then the stream is not in use. - * In those cases no other fields but these four can be used. - */ - s->video_dev = NULL; - s->dvb = NULL; - s->cx = cx; - s->type = type; - s->name = cx18_stream_info[type].name; - - /* Check whether the radio is supported */ - if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO)) - return 0; - - /* Check whether VBI is supported */ - if (type == CX18_ENC_STREAM_TYPE_VBI && - !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE))) - return 0; - - /* User explicitly selected 0 buffers for these streams, so don't - create them. */ - if (cx18_stream_info[type].dma != PCI_DMA_NONE && - cx->stream_buffers[type] == 0) { - CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name); - return 0; - } - - cx18_stream_init(cx, type); - - /* Allocate the cx18_dvb struct only for the TS on cards with DTV */ - if (type == CX18_ENC_STREAM_TYPE_TS) { - if (cx->card->hw_all & CX18_HW_DVB) { - s->dvb = kzalloc(sizeof(struct cx18_dvb), GFP_KERNEL); - if (s->dvb == NULL) { - CX18_ERR("Couldn't allocate cx18_dvb structure" - " for %s\n", s->name); - return -ENOMEM; - } - } else { - /* Don't need buffers for the TS, if there is no DVB */ - s->buffers = 0; - } - } - - if (num_offset == -1) - return 0; - - /* allocate and initialize the v4l2 video device structure */ - s->video_dev = video_device_alloc(); - if (s->video_dev == NULL) { - CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", - s->name); - return -ENOMEM; - } - - snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s", - cx->v4l2_dev.name, s->name); - - s->video_dev->num = num; - s->video_dev->v4l2_dev = &cx->v4l2_dev; - s->video_dev->fops = &cx18_v4l2_enc_fops; - s->video_dev->release = video_device_release; - s->video_dev->tvnorms = V4L2_STD_ALL; - s->video_dev->lock = &cx->serialize_lock; - set_bit(V4L2_FL_USE_FH_PRIO, &s->video_dev->flags); - cx18_set_funcs(s->video_dev); - return 0; -} - -/* Initialize v4l2 variables and register v4l2 devices */ -int cx18_streams_setup(struct cx18 *cx) -{ - int type, ret; - - /* Setup V4L2 Devices */ - for (type = 0; type < CX18_MAX_STREAMS; type++) { - /* Prepare device */ - ret = cx18_prep_dev(cx, type); - if (ret < 0) - break; - - /* Allocate Stream */ - ret = cx18_stream_alloc(&cx->streams[type]); - if (ret < 0) - break; - } - if (type == CX18_MAX_STREAMS) - return 0; - - /* One or more streams could not be initialized. Clean 'em all up. */ - cx18_streams_cleanup(cx, 0); - return ret; -} - -static int cx18_reg_dev(struct cx18 *cx, int type) -{ - struct cx18_stream *s = &cx->streams[type]; - int vfl_type = cx18_stream_info[type].vfl_type; - const char *name; - int num, ret; - - if (type == CX18_ENC_STREAM_TYPE_TS && s->dvb != NULL) { - ret = cx18_dvb_register(s); - if (ret < 0) { - CX18_ERR("DVB failed to register\n"); - return ret; - } - } - - if (s->video_dev == NULL) - return 0; - - num = s->video_dev->num; - /* card number + user defined offset + device offset */ - if (type != CX18_ENC_STREAM_TYPE_MPG) { - struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; - - if (s_mpg->video_dev) - num = s_mpg->video_dev->num - + cx18_stream_info[type].num_offset; - } - video_set_drvdata(s->video_dev, s); - - /* Register device. First try the desired minor, then any free one. */ - ret = video_register_device_no_warn(s->video_dev, vfl_type, num); - if (ret < 0) { - CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", - s->name, num); - video_device_release(s->video_dev); - s->video_dev = NULL; - return ret; - } - - name = video_device_node_name(s->video_dev); - - switch (vfl_type) { - case VFL_TYPE_GRABBER: - CX18_INFO("Registered device %s for %s (%d x %d.%02d kB)\n", - name, s->name, cx->stream_buffers[type], - cx->stream_buf_size[type] / 1024, - (cx->stream_buf_size[type] * 100 / 1024) % 100); - break; - - case VFL_TYPE_RADIO: - CX18_INFO("Registered device %s for %s\n", name, s->name); - break; - - case VFL_TYPE_VBI: - if (cx->stream_buffers[type]) - CX18_INFO("Registered device %s for %s " - "(%d x %d bytes)\n", - name, s->name, cx->stream_buffers[type], - cx->stream_buf_size[type]); - else - CX18_INFO("Registered device %s for %s\n", - name, s->name); - break; - } - - return 0; -} - -/* Register v4l2 devices */ -int cx18_streams_register(struct cx18 *cx) -{ - int type; - int err; - int ret = 0; - - /* Register V4L2 devices */ - for (type = 0; type < CX18_MAX_STREAMS; type++) { - err = cx18_reg_dev(cx, type); - if (err && ret == 0) - ret = err; - } - - if (ret == 0) - return 0; - - /* One or more streams could not be initialized. Clean 'em all up. */ - cx18_streams_cleanup(cx, 1); - return ret; -} - -/* Unregister v4l2 devices */ -void cx18_streams_cleanup(struct cx18 *cx, int unregister) -{ - struct video_device *vdev; - int type; - - /* Teardown all streams */ - for (type = 0; type < CX18_MAX_STREAMS; type++) { - - /* The TS has a cx18_dvb structure, not a video_device */ - if (type == CX18_ENC_STREAM_TYPE_TS) { - if (cx->streams[type].dvb != NULL) { - if (unregister) - cx18_dvb_unregister(&cx->streams[type]); - kfree(cx->streams[type].dvb); - cx->streams[type].dvb = NULL; - cx18_stream_free(&cx->streams[type]); - } - continue; - } - - /* No struct video_device, but can have buffers allocated */ - if (type == CX18_ENC_STREAM_TYPE_IDX) { - /* If the module params didn't inhibit IDX ... */ - if (cx->stream_buffers[type] != 0) { - cx->stream_buffers[type] = 0; - /* - * Before calling cx18_stream_free(), - * check if the IDX stream was actually set up. - * Needed, since the cx18_probe() error path - * exits through here as well as normal clean up - */ - if (cx->streams[type].buffers != 0) - cx18_stream_free(&cx->streams[type]); - } - continue; - } - - /* If struct video_device exists, can have buffers allocated */ - vdev = cx->streams[type].video_dev; - - cx->streams[type].video_dev = NULL; - if (vdev == NULL) - continue; - - if (type == CX18_ENC_STREAM_TYPE_YUV) - videobuf_mmap_free(&cx->streams[type].vbuf_q); - - cx18_stream_free(&cx->streams[type]); - - /* Unregister or release device */ - if (unregister) - video_unregister_device(vdev); - else - video_device_release(vdev); - } -} - -static void cx18_vbi_setup(struct cx18_stream *s) -{ - struct cx18 *cx = s->cx; - int raw = cx18_raw_vbi(cx); - u32 data[CX2341X_MBOX_MAX_DATA]; - int lines; - - if (cx->is_60hz) { - cx->vbi.count = 12; - cx->vbi.start[0] = 10; - cx->vbi.start[1] = 273; - } else { /* PAL/SECAM */ - cx->vbi.count = 18; - cx->vbi.start[0] = 6; - cx->vbi.start[1] = 318; - } - - /* setup VBI registers */ - if (raw) - v4l2_subdev_call(cx->sd_av, vbi, s_raw_fmt, &cx->vbi.in.fmt.vbi); - else - v4l2_subdev_call(cx->sd_av, vbi, s_sliced_fmt, &cx->vbi.in.fmt.sliced); - - /* - * Send the CX18_CPU_SET_RAW_VBI_PARAM API command to setup Encoder Raw - * VBI when the first analog capture channel starts, as once it starts - * (e.g. MPEG), we can't effect any change in the Encoder Raw VBI setup - * (i.e. for the VBI capture channels). We also send it for each - * analog capture channel anyway just to make sure we get the proper - * behavior - */ - if (raw) { - lines = cx->vbi.count * 2; - } else { - /* - * For 525/60 systems, according to the VIP 2 & BT.656 std: - * The EAV RP code's Field bit toggles on line 4, a few lines - * after the Vertcal Blank bit has already toggled. - * Tell the encoder to capture 21-4+1=18 lines per field, - * since we want lines 10 through 21. - * - * For 625/50 systems, according to the VIP 2 & BT.656 std: - * The EAV RP code's Field bit toggles on line 1, a few lines - * after the Vertcal Blank bit has already toggled. - * (We've actually set the digitizer so that the Field bit - * toggles on line 2.) Tell the encoder to capture 23-2+1=22 - * lines per field, since we want lines 6 through 23. - */ - lines = cx->is_60hz ? (21 - 4 + 1) * 2 : (23 - 2 + 1) * 2; - } - - data[0] = s->handle; - /* Lines per field */ - data[1] = (lines / 2) | ((lines / 2) << 16); - /* bytes per line */ - data[2] = (raw ? vbi_active_samples - : (cx->is_60hz ? vbi_hblank_samples_60Hz - : vbi_hblank_samples_50Hz)); - /* Every X number of frames a VBI interrupt arrives - (frames as in 25 or 30 fps) */ - data[3] = 1; - /* - * Set the SAV/EAV RP codes to look for as start/stop points - * when in VIP-1.1 mode - */ - if (raw) { - /* - * Start codes for beginning of "active" line in vertical blank - * 0x20 ( VerticalBlank ) - * 0x60 ( EvenField VerticalBlank ) - */ - data[4] = 0x20602060; - /* - * End codes for end of "active" raw lines and regular lines - * 0x30 ( VerticalBlank HorizontalBlank) - * 0x70 ( EvenField VerticalBlank HorizontalBlank) - * 0x90 (Task HorizontalBlank) - * 0xd0 (Task EvenField HorizontalBlank) - */ - data[5] = 0x307090d0; - } else { - /* - * End codes for active video, we want data in the hblank region - * 0xb0 (Task 0 VerticalBlank HorizontalBlank) - * 0xf0 (Task EvenField VerticalBlank HorizontalBlank) - * - * Since the V bit is only allowed to toggle in the EAV RP code, - * just before the first active region line, these two - * are problematic: - * 0x90 (Task HorizontalBlank) - * 0xd0 (Task EvenField HorizontalBlank) - * - * We have set the digitzer such that we don't have to worry - * about these problem codes. - */ - data[4] = 0xB0F0B0F0; - /* - * Start codes for beginning of active line in vertical blank - * 0xa0 (Task VerticalBlank ) - * 0xe0 (Task EvenField VerticalBlank ) - */ - data[5] = 0xA0E0A0E0; - } - - CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n", - data[0], data[1], data[2], data[3], data[4], data[5]); - - cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data); -} - -void cx18_stream_rotate_idx_mdls(struct cx18 *cx) -{ - struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - struct cx18_mdl *mdl; - - if (!cx18_stream_enabled(s)) - return; - - /* Return if the firmware is not running low on MDLs */ - if ((atomic_read(&s->q_free.depth) + atomic_read(&s->q_busy.depth)) >= - CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN) - return; - - /* Return if there are no MDLs to rotate back to the firmware */ - if (atomic_read(&s->q_full.depth) < 2) - return; - - /* - * Take the oldest IDX MDL still holding data, and discard its index - * entries by scheduling the MDL to go back to the firmware - */ - mdl = cx18_dequeue(s, &s->q_full); - if (mdl != NULL) - cx18_enqueue(s, mdl, &s->q_free); -} - -static -struct cx18_queue *_cx18_stream_put_mdl_fw(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - struct cx18 *cx = s->cx; - struct cx18_queue *q; - - /* Don't give it to the firmware, if we're not running a capture */ - if (s->handle == CX18_INVALID_TASK_HANDLE || - test_bit(CX18_F_S_STOPPING, &s->s_flags) || - !test_bit(CX18_F_S_STREAMING, &s->s_flags)) - return cx18_enqueue(s, mdl, &s->q_free); - - q = cx18_enqueue(s, mdl, &s->q_busy); - if (q != &s->q_busy) - return q; /* The firmware has the max MDLs it can handle */ - - cx18_mdl_sync_for_device(s, mdl); - cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle, - (void __iomem *) &cx->scb->cpu_mdl[mdl->id] - cx->enc_mem, - s->bufs_per_mdl, mdl->id, s->mdl_size); - return q; -} - -static -void _cx18_stream_load_fw_queue(struct cx18_stream *s) -{ - struct cx18_queue *q; - struct cx18_mdl *mdl; - - if (atomic_read(&s->q_free.depth) == 0 || - atomic_read(&s->q_busy.depth) >= CX18_MAX_FW_MDLS_PER_STREAM) - return; - - /* Move from q_free to q_busy notifying the firmware, until the limit */ - do { - mdl = cx18_dequeue(s, &s->q_free); - if (mdl == NULL) - break; - q = _cx18_stream_put_mdl_fw(s, mdl); - } while (atomic_read(&s->q_busy.depth) < CX18_MAX_FW_MDLS_PER_STREAM - && q == &s->q_busy); -} - -void cx18_out_work_handler(struct work_struct *work) -{ - struct cx18_stream *s = - container_of(work, struct cx18_stream, out_work_order); - - _cx18_stream_load_fw_queue(s); -} - -static void cx18_stream_configure_mdls(struct cx18_stream *s) -{ - cx18_unload_queues(s); - - switch (s->type) { - case CX18_ENC_STREAM_TYPE_YUV: - /* - * Height should be a multiple of 32 lines. - * Set the MDL size to the exact size needed for one frame. - * Use enough buffers per MDL to cover the MDL size - */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) - s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2; - else - s->mdl_size = 720 * s->cx->cxhdl.height * 2; - s->bufs_per_mdl = s->mdl_size / s->buf_size; - if (s->mdl_size % s->buf_size) - s->bufs_per_mdl++; - break; - case CX18_ENC_STREAM_TYPE_VBI: - s->bufs_per_mdl = 1; - if (cx18_raw_vbi(s->cx)) { - s->mdl_size = (s->cx->is_60hz ? 12 : 18) - * 2 * vbi_active_samples; - } else { - /* - * See comment in cx18_vbi_setup() below about the - * extra lines we capture in sliced VBI mode due to - * the lines on which EAV RP codes toggle. - */ - s->mdl_size = s->cx->is_60hz - ? (21 - 4 + 1) * 2 * vbi_hblank_samples_60Hz - : (23 - 2 + 1) * 2 * vbi_hblank_samples_50Hz; - } - break; - default: - s->bufs_per_mdl = 1; - s->mdl_size = s->buf_size * s->bufs_per_mdl; - break; - } - - cx18_load_queues(s); -} - -int cx18_start_v4l2_encode_stream(struct cx18_stream *s) -{ - u32 data[MAX_MB_ARGUMENTS]; - struct cx18 *cx = s->cx; - int captype = 0; - struct cx18_stream *s_idx; - - if (!cx18_stream_enabled(s)) - return -EINVAL; - - CX18_DEBUG_INFO("Start encoder stream %s\n", s->name); - - switch (s->type) { - case CX18_ENC_STREAM_TYPE_MPG: - captype = CAPTURE_CHANNEL_TYPE_MPEG; - cx->mpg_data_received = cx->vbi_data_inserted = 0; - cx->dualwatch_jiffies = jiffies; - cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode); - cx->search_pack_header = 0; - break; - - case CX18_ENC_STREAM_TYPE_IDX: - captype = CAPTURE_CHANNEL_TYPE_INDEX; - break; - case CX18_ENC_STREAM_TYPE_TS: - captype = CAPTURE_CHANNEL_TYPE_TS; - break; - case CX18_ENC_STREAM_TYPE_YUV: - captype = CAPTURE_CHANNEL_TYPE_YUV; - break; - case CX18_ENC_STREAM_TYPE_PCM: - captype = CAPTURE_CHANNEL_TYPE_PCM; - break; - case CX18_ENC_STREAM_TYPE_VBI: -#ifdef CX18_ENCODER_PARSES_SLICED - captype = cx18_raw_vbi(cx) ? - CAPTURE_CHANNEL_TYPE_VBI : CAPTURE_CHANNEL_TYPE_SLICED_VBI; -#else - /* - * Currently we set things up so that Sliced VBI from the - * digitizer is handled as Raw VBI by the encoder - */ - captype = CAPTURE_CHANNEL_TYPE_VBI; -#endif - cx->vbi.frame = 0; - cx->vbi.inserted_frame = 0; - memset(cx->vbi.sliced_mpeg_size, - 0, sizeof(cx->vbi.sliced_mpeg_size)); - break; - default: - return -EINVAL; - } - - /* Clear Streamoff flags in case left from last capture */ - clear_bit(CX18_F_S_STREAMOFF, &s->s_flags); - - cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE); - s->handle = data[0]; - cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype); - - /* - * For everything but CAPTURE_CHANNEL_TYPE_TS, play it safe and - * set up all the parameters, as it is not obvious which parameters the - * firmware shares across capture channel types and which it does not. - * - * Some of the cx18_vapi() calls below apply to only certain capture - * channel types. We're hoping there's no harm in calling most of them - * anyway, as long as the values are all consistent. Setting some - * shared parameters will have no effect once an analog capture channel - * has started streaming. - */ - if (captype != CAPTURE_CHANNEL_TYPE_TS) { - cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0); - cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1); - cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0); - cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1); - - /* - * Audio related reset according to - * Documentation/video4linux/cx2341x/fw-encoder-api.txt - */ - if (atomic_read(&cx->ana_capturing) == 0) - cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, - s->handle, 12); - - /* - * Number of lines for Field 1 & Field 2 according to - * Documentation/video4linux/cx2341x/fw-encoder-api.txt - * Field 1 is 312 for 625 line systems in BT.656 - * Field 2 is 313 for 625 line systems in BT.656 - */ - cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3, - s->handle, 312, 313); - - if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE) - cx18_vbi_setup(s); - - /* - * Select to receive I, P, and B frame index entries, if the - * index stream is enabled. Otherwise disable index entry - * generation. - */ - s_idx = &cx->streams[CX18_ENC_STREAM_TYPE_IDX]; - cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 2, - s->handle, cx18_stream_enabled(s_idx) ? 7 : 0); - - /* Call out to the common CX2341x API setup for user controls */ - cx->cxhdl.priv = s; - cx2341x_handler_setup(&cx->cxhdl); - - /* - * When starting a capture and we're set for radio, - * ensure the video is muted, despite the user control. - */ - if (!cx->cxhdl.video_mute && - test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) - cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle, - (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1); - - /* Enable the Video Format Converter for UYVY 4:2:2 support, - * rather than the default HM12 Macroblovk 4:2:0 support. - */ - if (captype == CAPTURE_CHANNEL_TYPE_YUV) { - if (s->pixelformat == V4L2_PIX_FMT_UYVY) - cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, - s->handle, 1); - else - /* If in doubt, default to HM12 */ - cx18_vapi(cx, CX18_CPU_SET_VFC_PARAM, 2, - s->handle, 0); - } - } - - if (atomic_read(&cx->tot_capturing) == 0) { - cx2341x_handler_set_busy(&cx->cxhdl, 1); - clear_bit(CX18_F_I_EOS, &cx->i_flags); - cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK); - } - - cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle, - (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem, - (void __iomem *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem); - - /* Init all the cpu_mdls for this stream */ - cx18_stream_configure_mdls(s); - _cx18_stream_load_fw_queue(s); - - /* begin_capture */ - if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) { - CX18_DEBUG_WARN("Error starting capture!\n"); - /* Ensure we're really not capturing before releasing MDLs */ - set_bit(CX18_F_S_STOPPING, &s->s_flags); - if (s->type == CX18_ENC_STREAM_TYPE_MPG) - cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, 1); - else - cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); - clear_bit(CX18_F_S_STREAMING, &s->s_flags); - /* FIXME - CX18_F_S_STREAMOFF as well? */ - cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); - cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); - s->handle = CX18_INVALID_TASK_HANDLE; - clear_bit(CX18_F_S_STOPPING, &s->s_flags); - if (atomic_read(&cx->tot_capturing) == 0) { - set_bit(CX18_F_I_EOS, &cx->i_flags); - cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); - } - return -EINVAL; - } - - /* you're live! sit back and await interrupts :) */ - if (captype != CAPTURE_CHANNEL_TYPE_TS) - atomic_inc(&cx->ana_capturing); - atomic_inc(&cx->tot_capturing); - return 0; -} -EXPORT_SYMBOL(cx18_start_v4l2_encode_stream); - -void cx18_stop_all_captures(struct cx18 *cx) -{ - int i; - - for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) { - struct cx18_stream *s = &cx->streams[i]; - - if (!cx18_stream_enabled(s)) - continue; - if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) - cx18_stop_v4l2_encode_stream(s, 0); - } -} - -int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end) -{ - struct cx18 *cx = s->cx; - - if (!cx18_stream_enabled(s)) - return -EINVAL; - - /* This function assumes that you are allowed to stop the capture - and that we are actually capturing */ - - CX18_DEBUG_INFO("Stop Capture\n"); - - if (atomic_read(&cx->tot_capturing) == 0) - return 0; - - set_bit(CX18_F_S_STOPPING, &s->s_flags); - if (s->type == CX18_ENC_STREAM_TYPE_MPG) - cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end); - else - cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle); - - if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) { - CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n"); - } - - if (s->type != CX18_ENC_STREAM_TYPE_TS) - atomic_dec(&cx->ana_capturing); - atomic_dec(&cx->tot_capturing); - - /* Clear capture and no-read bits */ - clear_bit(CX18_F_S_STREAMING, &s->s_flags); - - /* Tell the CX23418 it can't use our buffers anymore */ - cx18_vapi(cx, CX18_CPU_DE_RELEASE_MDL, 1, s->handle); - - cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle); - s->handle = CX18_INVALID_TASK_HANDLE; - clear_bit(CX18_F_S_STOPPING, &s->s_flags); - - if (atomic_read(&cx->tot_capturing) > 0) - return 0; - - cx2341x_handler_set_busy(&cx->cxhdl, 0); - cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK); - wake_up(&s->waitq); - - return 0; -} -EXPORT_SYMBOL(cx18_stop_v4l2_encode_stream); - -u32 cx18_find_handle(struct cx18 *cx) -{ - int i; - - /* find first available handle to be used for global settings */ - for (i = 0; i < CX18_MAX_STREAMS; i++) { - struct cx18_stream *s = &cx->streams[i]; - - if (s->video_dev && (s->handle != CX18_INVALID_TASK_HANDLE)) - return s->handle; - } - return CX18_INVALID_TASK_HANDLE; -} - -struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle) -{ - int i; - struct cx18_stream *s; - - if (handle == CX18_INVALID_TASK_HANDLE) - return NULL; - - for (i = 0; i < CX18_MAX_STREAMS; i++) { - s = &cx->streams[i]; - if (s->handle != handle) - continue; - if (cx18_stream_enabled(s)) - return s; - } - return NULL; -} diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h deleted file mode 100644 index 713b0e61536..00000000000 --- a/drivers/media/video/cx18/cx18-streams.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * cx18 init/start/stop/exit stream functions - * - * Derived from ivtv-streams.h - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -u32 cx18_find_handle(struct cx18 *cx); -struct cx18_stream *cx18_handle_to_stream(struct cx18 *cx, u32 handle); -int cx18_streams_setup(struct cx18 *cx); -int cx18_streams_register(struct cx18 *cx); -void cx18_streams_cleanup(struct cx18 *cx, int unregister); - -#define CX18_ENC_STREAM_TYPE_IDX_FW_MDL_MIN (3) -void cx18_stream_rotate_idx_mdls(struct cx18 *cx); - -static inline bool cx18_stream_enabled(struct cx18_stream *s) -{ - return s->video_dev || - (s->dvb && s->dvb->enabled) || - (s->type == CX18_ENC_STREAM_TYPE_IDX && - s->cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] != 0); -} - -/* Related to submission of mdls to firmware */ -static inline void cx18_stream_load_fw_queue(struct cx18_stream *s) -{ - schedule_work(&s->out_work_order); -} - -static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s, - struct cx18_mdl *mdl) -{ - /* Put mdl on q_free; the out work handler will move mdl(s) to q_busy */ - cx18_enqueue(s, mdl, &s->q_free); - cx18_stream_load_fw_queue(s); -} - -void cx18_out_work_handler(struct work_struct *work); - -/* Capture related */ -int cx18_start_v4l2_encode_stream(struct cx18_stream *s); -int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end); - -void cx18_stop_all_captures(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c deleted file mode 100644 index 6d3121ff45a..00000000000 --- a/drivers/media/video/cx18/cx18-vbi.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * cx18 Vertical Blank Interval support functions - * - * Derived from ivtv-vbi.c - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-vbi.h" -#include "cx18-ioctl.h" -#include "cx18-queue.h" - -/* - * Raster Reference/Protection (RP) bytes, used in Start/End Active - * Video codes emitted from the digitzer in VIP 1.x mode, that flag the start - * of VBI sample or VBI ancillary data regions in the digitial ratser line. - * - * Task FieldEven VerticalBlank HorizontalBlank 0 0 0 0 - */ -static const u8 raw_vbi_sav_rp[2] = { 0x20, 0x60 }; /* __V_, _FV_ */ -static const u8 sliced_vbi_eav_rp[2] = { 0xb0, 0xf0 }; /* T_VH, TFVH */ - -static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp) -{ - int line = 0; - int i; - u32 linemask[2] = { 0, 0 }; - unsigned short size; - static const u8 mpeg_hdr_data[] = { - /* MPEG-2 Program Pack */ - 0x00, 0x00, 0x01, 0xba, /* Prog Pack start code */ - 0x44, 0x00, 0x0c, 0x66, 0x24, 0x01, /* SCR, SCR Ext, markers */ - 0x01, 0xd1, 0xd3, /* Mux Rate, markers */ - 0xfa, 0xff, 0xff, /* Res, Suff cnt, Stuff */ - /* MPEG-2 Private Stream 1 PES Packet */ - 0x00, 0x00, 0x01, 0xbd, /* Priv Stream 1 start */ - 0x00, 0x1a, /* length */ - 0x84, 0x80, 0x07, /* flags, hdr data len */ - 0x21, 0x00, 0x5d, 0x63, 0xa7, /* PTS, markers */ - 0xff, 0xff /* stuffing */ - }; - const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */ - int idx = cx->vbi.frame % CX18_VBI_FRAMES; - u8 *dst = &cx->vbi.sliced_mpeg_data[idx][0]; - - for (i = 0; i < lines; i++) { - struct v4l2_sliced_vbi_data *sdata = cx->vbi.sliced_data + i; - int f, l; - - if (sdata->id == 0) - continue; - - l = sdata->line - 6; - f = sdata->field; - if (f) - l += 18; - if (l < 32) - linemask[0] |= (1 << l); - else - linemask[1] |= (1 << (l - 32)); - dst[sd + 12 + line * 43] = cx18_service2vbi(sdata->id); - memcpy(dst + sd + 12 + line * 43 + 1, sdata->data, 42); - line++; - } - memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data)); - if (line == 36) { - /* All lines are used, so there is no space for the linemask - (the max size of the VBI data is 36 * 43 + 4 bytes). - So in this case we use the magic number 'ITV0'. */ - memcpy(dst + sd, "ITV0", 4); - memcpy(dst + sd + 4, dst + sd + 12, line * 43); - size = 4 + ((43 * line + 3) & ~3); - } else { - memcpy(dst + sd, "itv0", 4); - cpu_to_le32s(&linemask[0]); - cpu_to_le32s(&linemask[1]); - memcpy(dst + sd + 4, &linemask[0], 8); - size = 12 + ((43 * line + 3) & ~3); - } - dst[4+16] = (size + 10) >> 8; - dst[5+16] = (size + 10) & 0xff; - dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6); - dst[10+16] = (pts_stamp >> 22) & 0xff; - dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff); - dst[12+16] = (pts_stamp >> 7) & 0xff; - dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1); - cx->vbi.sliced_mpeg_size[idx] = sd + size; -} - -/* Compress raw VBI format, removes leading SAV codes and surplus space - after the frame. Returns new compressed size. */ -/* FIXME - this function ignores the input size. */ -static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size, u32 hdr_size) -{ - u32 line_size = vbi_active_samples; - u32 lines = cx->vbi.count * 2; - u8 *q = buf; - u8 *p; - int i; - - /* Skip the header */ - buf += hdr_size; - - for (i = 0; i < lines; i++) { - p = buf + i * line_size; - - /* Look for SAV code */ - if (p[0] != 0xff || p[1] || p[2] || - (p[3] != raw_vbi_sav_rp[0] && - p[3] != raw_vbi_sav_rp[1])) - break; - if (i == lines - 1) { - /* last line is hdr_size bytes short - extrapolate it */ - memcpy(q, p + 4, line_size - 4 - hdr_size); - q += line_size - 4 - hdr_size; - p += line_size - hdr_size - 1; - memset(q, (int) *p, hdr_size); - } else { - memcpy(q, p + 4, line_size - 4); - q += line_size - 4; - } - } - return lines * (line_size - 4); -} - -static u32 compress_sliced_buf(struct cx18 *cx, u8 *buf, u32 size, - const u32 hdr_size) -{ - struct v4l2_decode_vbi_line vbi; - int i; - u32 line = 0; - u32 line_size = cx->is_60hz ? vbi_hblank_samples_60Hz - : vbi_hblank_samples_50Hz; - - /* find the first valid line */ - for (i = hdr_size, buf += hdr_size; i < size; i++, buf++) { - if (buf[0] == 0xff && !buf[1] && !buf[2] && - (buf[3] == sliced_vbi_eav_rp[0] || - buf[3] == sliced_vbi_eav_rp[1])) - break; - } - - /* - * The last line is short by hdr_size bytes, but for the remaining - * checks against size, we pretend that it is not, by counting the - * header bytes we knowingly skipped - */ - size -= (i - hdr_size); - if (size < line_size) - return line; - - for (i = 0; i < size / line_size; i++) { - u8 *p = buf + i * line_size; - - /* Look for EAV code */ - if (p[0] != 0xff || p[1] || p[2] || - (p[3] != sliced_vbi_eav_rp[0] && - p[3] != sliced_vbi_eav_rp[1])) - continue; - vbi.p = p + 4; - v4l2_subdev_call(cx->sd_av, vbi, decode_vbi_line, &vbi); - if (vbi.type) { - cx->vbi.sliced_data[line].id = vbi.type; - cx->vbi.sliced_data[line].field = vbi.is_second_field; - cx->vbi.sliced_data[line].line = vbi.line; - memcpy(cx->vbi.sliced_data[line].data, vbi.p, 42); - line++; - } - } - return line; -} - -static void _cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf) -{ - /* - * The CX23418 provides a 12 byte header in its raw VBI buffers to us: - * 0x3fffffff [4 bytes of something] [4 byte presentation time stamp] - */ - struct vbi_data_hdr { - __be32 magic; - __be32 unknown; - __be32 pts; - } *hdr = (struct vbi_data_hdr *) buf->buf; - - u8 *p = (u8 *) buf->buf; - u32 size = buf->bytesused; - u32 pts; - int lines; - - /* - * The CX23418 sends us data that is 32 bit little-endian swapped, - * but we want the raw VBI bytes in the order they were in the raster - * line. This has a side effect of making the header big endian - */ - cx18_buf_swap(buf); - - /* Raw VBI data */ - if (cx18_raw_vbi(cx)) { - - size = buf->bytesused = - compress_raw_buf(cx, p, size, sizeof(struct vbi_data_hdr)); - - /* - * Hack needed for compatibility with old VBI software. - * Write the frame # at the last 4 bytes of the frame - */ - p += size - 4; - memcpy(p, &cx->vbi.frame, 4); - cx->vbi.frame++; - return; - } - - /* Sliced VBI data with data insertion */ - - pts = (be32_to_cpu(hdr->magic) == 0x3fffffff) ? be32_to_cpu(hdr->pts) - : 0; - - lines = compress_sliced_buf(cx, p, size, sizeof(struct vbi_data_hdr)); - - /* always return at least one empty line */ - if (lines == 0) { - cx->vbi.sliced_data[0].id = 0; - cx->vbi.sliced_data[0].line = 0; - cx->vbi.sliced_data[0].field = 0; - lines = 1; - } - buf->bytesused = size = lines * sizeof(cx->vbi.sliced_data[0]); - memcpy(p, &cx->vbi.sliced_data[0], size); - - if (cx->vbi.insert_mpeg) - copy_vbi_data(cx, lines, pts); - cx->vbi.frame++; -} - -void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl, - int streamtype) -{ - struct cx18_buffer *buf; - u32 orig_used; - - if (streamtype != CX18_ENC_STREAM_TYPE_VBI) - return; - - /* - * Big assumption here: - * Every buffer hooked to the MDL's buf_list is a complete VBI frame - * that ends at the end of the buffer. - * - * To assume anything else would make the code in this file - * more complex, or require extra memcpy()'s to make the - * buffers satisfy the above assumption. It's just simpler to set - * up the encoder buffer transfers to make the assumption true. - */ - list_for_each_entry(buf, &mdl->buf_list, list) { - orig_used = buf->bytesused; - if (orig_used == 0) - break; - _cx18_process_vbi_data(cx, buf); - mdl->bytesused -= (orig_used - buf->bytesused); - } -} diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/video/cx18/cx18-vbi.h deleted file mode 100644 index b365cf4b466..00000000000 --- a/drivers/media/video/cx18/cx18-vbi.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * cx18 Vertical Blank Interval support functions - * - * Derived from ivtv-vbi.h - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -void cx18_process_vbi_data(struct cx18 *cx, struct cx18_mdl *mdl, - int streamtype); -int cx18_used_line(struct cx18 *cx, int line, int field); diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h deleted file mode 100644 index fed48b6bb67..00000000000 --- a/drivers/media/video/cx18/cx18-version.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * cx18 driver version information - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#ifndef CX18_VERSION_H -#define CX18_VERSION_H - -#define CX18_DRIVER_NAME "cx18" -#define CX18_VERSION "1.5.1" - -#endif diff --git a/drivers/media/video/cx18/cx18-video.c b/drivers/media/video/cx18/cx18-video.c deleted file mode 100644 index 6dc84aac8f4..00000000000 --- a/drivers/media/video/cx18/cx18-video.c +++ /dev/null @@ -1,32 +0,0 @@ -/* - * cx18 video interface functions - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#include "cx18-driver.h" -#include "cx18-video.h" -#include "cx18-cards.h" - -void cx18_video_set_io(struct cx18 *cx) -{ - int inp = cx->active_input; - - v4l2_subdev_call(cx->sd_av, video, s_routing, - cx->card->video_inputs[inp].video_input, 0, 0); -} diff --git a/drivers/media/video/cx18/cx18-video.h b/drivers/media/video/cx18/cx18-video.h deleted file mode 100644 index 529006a06e5..00000000000 --- a/drivers/media/video/cx18/cx18-video.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * cx18 video interface functions - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -void cx18_video_set_io(struct cx18 *cx); diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h deleted file mode 100644 index 767a8d23e3f..00000000000 --- a/drivers/media/video/cx18/cx23418.h +++ /dev/null @@ -1,492 +0,0 @@ -/* - * cx18 header containing common defines. - * - * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307 USA - */ - -#ifndef CX23418_H -#define CX23418_H - -#include <media/cx2341x.h> - -#define MGR_CMD_MASK 0x40000000 -/* The MSB of the command code indicates that this is the completion of a - command */ -#define MGR_CMD_MASK_ACK (MGR_CMD_MASK | 0x80000000) - -/* Description: This command creates a new instance of a certain task - IN[0] - Task ID. This is one of the XPU_CMD_MASK_YYY where XPU is - the processor on which the task YYY will be created - OUT[0] - Task handle. This handle is passed along with commands to - dispatch to the right instance of the task - ReturnCode - One of the ERR_SYS_... */ -#define CX18_CREATE_TASK (MGR_CMD_MASK | 0x0001) - -/* Description: This command destroys an instance of a task - IN[0] - Task handle. Hanlde of the task to destroy - ReturnCode - One of the ERR_SYS_... */ -#define CX18_DESTROY_TASK (MGR_CMD_MASK | 0x0002) - -/* All commands for CPU have the following mask set */ -#define CPU_CMD_MASK 0x20000000 -#define CPU_CMD_MASK_DEBUG (CPU_CMD_MASK | 0x00000000) -#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000) -#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000) -#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000) - -#define EPU_CMD_MASK 0x02000000 -#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000) -#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000) - -#define APU_CMD_MASK 0x10000000 -#define APU_CMD_MASK_ACK (APU_CMD_MASK | 0x80000000) - -#define CX18_APU_ENCODING_METHOD_MPEG (0 << 28) -#define CX18_APU_ENCODING_METHOD_AC3 (1 << 28) - -/* Description: Command APU to start audio - IN[0] - audio parameters (same as CX18_CPU_SET_AUDIO_PARAMETERS?) - IN[1] - caller buffer address, or 0 - ReturnCode - ??? */ -#define CX18_APU_START (APU_CMD_MASK | 0x01) - -/* Description: Command APU to stop audio - IN[0] - encoding method to stop - ReturnCode - ??? */ -#define CX18_APU_STOP (APU_CMD_MASK | 0x02) - -/* Description: Command APU to reset the AI - ReturnCode - ??? */ -#define CX18_APU_RESETAI (APU_CMD_MASK | 0x05) - -/* Description: This command indicates that a Memory Descriptor List has been - filled with the requested channel type - IN[0] - Task handle. Handle of the task - IN[1] - Offset of the MDL_ACK from the beginning of the local DDR. - IN[2] - Number of CNXT_MDL_ACK structures in the array pointed to by IN[1] - ReturnCode - One of the ERR_DE_... */ -#define CX18_EPU_DMA_DONE (EPU_CMD_MASK_DE | 0x0001) - -/* Something interesting happened - IN[0] - A value to log - IN[1] - An offset of a string in the MiniMe memory; - 0/zero/NULL means "I have nothing to say" */ -#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003) - -/* Reads memory/registers (32-bit) - IN[0] - Address - OUT[1] - Value */ -#define CX18_CPU_DEBUG_PEEK32 (CPU_CMD_MASK_DEBUG | 0x0003) - -/* Description: This command starts streaming with the set channel type - IN[0] - Task handle. Handle of the task to start - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_CAPTURE_START (CPU_CMD_MASK_CAPTURE | 0x0002) - -/* Description: This command stops streaming with the set channel type - IN[0] - Task handle. Handle of the task to stop - IN[1] - 0 = stop at end of GOP, 1 = stop at end of frame (MPEG only) - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_CAPTURE_STOP (CPU_CMD_MASK_CAPTURE | 0x0003) - -/* Description: This command pauses streaming with the set channel type - IN[0] - Task handle. Handle of the task to pause - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_CAPTURE_PAUSE (CPU_CMD_MASK_CAPTURE | 0x0007) - -/* Description: This command resumes streaming with the set channel type - IN[0] - Task handle. Handle of the task to resume - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_CAPTURE_RESUME (CPU_CMD_MASK_CAPTURE | 0x0008) - -#define CAPTURE_CHANNEL_TYPE_NONE 0 -#define CAPTURE_CHANNEL_TYPE_MPEG 1 -#define CAPTURE_CHANNEL_TYPE_INDEX 2 -#define CAPTURE_CHANNEL_TYPE_YUV 3 -#define CAPTURE_CHANNEL_TYPE_PCM 4 -#define CAPTURE_CHANNEL_TYPE_VBI 5 -#define CAPTURE_CHANNEL_TYPE_SLICED_VBI 6 -#define CAPTURE_CHANNEL_TYPE_TS 7 -#define CAPTURE_CHANNEL_TYPE_MAX 15 - -/* Description: This command sets the channel type. This can only be done - when stopped. - IN[0] - Task handle. Handle of the task to start - IN[1] - Channel Type. See Below. - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_CHANNEL_TYPE (CPU_CMD_MASK_CAPTURE + 1) - -/* Description: Set stream output type - IN[0] - task handle. Handle of the task to start - IN[1] - type - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_STREAM_OUTPUT_TYPE (CPU_CMD_MASK_CAPTURE | 0x0012) - -/* Description: Set video input resolution and frame rate - IN[0] - task handle - IN[1] - reserved - IN[2] - reserved - IN[3] - reserved - IN[4] - reserved - IN[5] - frame rate, 0 - 29.97f/s, 1 - 25f/s - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VIDEO_IN (CPU_CMD_MASK_CAPTURE | 0x0004) - -/* Description: Set video frame rate - IN[0] - task handle. Handle of the task to start - IN[1] - video bit rate mode - IN[2] - video average rate - IN[3] - video peak rate - IN[4] - system mux rate - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VIDEO_RATE (CPU_CMD_MASK_CAPTURE | 0x0005) - -/* Description: Set video output resolution - IN[0] - task handle - IN[1] - horizontal size - IN[2] - vertical size - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VIDEO_RESOLUTION (CPU_CMD_MASK_CAPTURE | 0x0006) - -/* Description: This command set filter parameters - IN[0] - Task handle. Handle of the task - IN[1] - type, 0 - temporal, 1 - spatial, 2 - median - IN[2] - mode, temporal/spatial: 0 - disable, 1 - static, 2 - dynamic - median: 0 = disable, 1 = horizontal, 2 = vertical, - 3 = horizontal/vertical, 4 = diagonal - IN[3] - strength, temporal 0 - 31, spatial 0 - 15 - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_FILTER_PARAM (CPU_CMD_MASK_CAPTURE | 0x0009) - -/* Description: This command set spatial filter type - IN[0] - Task handle. - IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only, - 3 = 2D H/V separable, 4 = 2D symmetric non-separable - IN[2] - chroma type: 0 - disable, 1 = 1D horizontal - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C) - -/* Description: This command set coring levels for median filter - IN[0] - Task handle. - IN[1] - luma_high - IN[2] - luma_low - IN[3] - chroma_high - IN[4] - chroma_low - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_MEDIAN_CORING (CPU_CMD_MASK_CAPTURE | 0x000E) - -/* Description: This command set the picture type mask for index file - IN[0] - Task handle (ignored by firmware) - IN[1] - 0 = disable index file output - 1 = output I picture - 2 = P picture - 4 = B picture - other = illegal */ -#define CX18_CPU_SET_INDEXTABLE (CPU_CMD_MASK_CAPTURE | 0x0010) - -/* Description: Set audio parameters - IN[0] - task handle. Handle of the task to start - IN[1] - audio parameter - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_AUDIO_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0011) - -/* Description: Set video mute - IN[0] - task handle. Handle of the task to start - IN[1] - bit31-24: muteYvalue - bit23-16: muteUvalue - bit15-8: muteVvalue - bit0: 1:mute, 0: unmute - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VIDEO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0013) - -/* Description: Set audio mute - IN[0] - task handle. Handle of the task to start - IN[1] - mute/unmute - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_AUDIO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0014) - -/* Description: Set stream output type - IN[0] - task handle. Handle of the task to start - IN[1] - subType - SET_INITIAL_SCR 1 - SET_QUALITY_MODE 2 - SET_VIM_PROTECT_MODE 3 - SET_PTS_CORRECTION 4 - SET_USB_FLUSH_MODE 5 - SET_MERAQPAR_ENABLE 6 - SET_NAV_PACK_INSERTION 7 - SET_SCENE_CHANGE_ENABLE 8 - IN[2] - parameter 1 - IN[3] - parameter 2 - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_MISC_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0015) - -/* Description: Set raw VBI parameters - IN[0] - Task handle - IN[1] - No. of input lines per field: - bit[15:0]: field 1, - bit[31:16]: field 2 - IN[2] - No. of input bytes per line - IN[3] - No. of output frames per transfer - IN[4] - start code - IN[5] - stop code - ReturnCode */ -#define CX18_CPU_SET_RAW_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0016) - -/* Description: Set capture line No. - IN[0] - task handle. Handle of the task to start - IN[1] - height1 - IN[2] - height2 - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_CAPTURE_LINE_NO (CPU_CMD_MASK_CAPTURE | 0x0017) - -/* Description: Set copyright - IN[0] - task handle. Handle of the task to start - IN[1] - copyright - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_COPYRIGHT (CPU_CMD_MASK_CAPTURE | 0x0018) - -/* Description: Set audio PID - IN[0] - task handle. Handle of the task to start - IN[1] - PID - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_AUDIO_PID (CPU_CMD_MASK_CAPTURE | 0x0019) - -/* Description: Set video PID - IN[0] - task handle. Handle of the task to start - IN[1] - PID - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VIDEO_PID (CPU_CMD_MASK_CAPTURE | 0x001A) - -/* Description: Set Vertical Crop Line - IN[0] - task handle. Handle of the task to start - IN[1] - Line - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_VER_CROP_LINE (CPU_CMD_MASK_CAPTURE | 0x001B) - -/* Description: Set COP structure - IN[0] - task handle. Handle of the task to start - IN[1] - M - IN[2] - N - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_GOP_STRUCTURE (CPU_CMD_MASK_CAPTURE | 0x001C) - -/* Description: Set Scene Change Detection - IN[0] - task handle. Handle of the task to start - IN[1] - scene change - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_SCENE_CHANGE_DETECTION (CPU_CMD_MASK_CAPTURE | 0x001D) - -/* Description: Set Aspect Ratio - IN[0] - task handle. Handle of the task to start - IN[1] - AspectRatio - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_ASPECT_RATIO (CPU_CMD_MASK_CAPTURE | 0x001E) - -/* Description: Set Skip Input Frame - IN[0] - task handle. Handle of the task to start - IN[1] - skip input frames - ReturnCode - One of the ERR_CAPTURE_... */ -#define CX18_CPU_SET_SKIP_INPUT_FRAME (CPU_CMD_MASK_CAPTURE | 0x001F) - -/* Description: Set sliced VBI parameters - - Note This API will only apply to MPEG and Sliced VBI Channels - IN[0] - Task handle - IN[1] - output type, 0 - CC, 1 - Moji, 2 - Teletext - IN[2] - start / stop line - bit[15:0] start line number - bit[31:16] stop line number - IN[3] - number of output frames per interrupt - IN[4] - VBI insertion mode - bit 0: output user data, 1 - enable - bit 1: output private stream, 1 - enable - bit 2: mux option, 0 - in GOP, 1 - in picture - bit[7:0] private stream ID - IN[5] - insertion period while mux option is in picture - ReturnCode - VBI data offset */ -#define CX18_CPU_SET_SLICED_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0020) - -/* Description: Set the user data place holder - IN[0] - type of data (0 for user) - IN[1] - Stuffing period - IN[2] - ID data size in word (less than 10) - IN[3] - Pointer to ID buffer */ -#define CX18_CPU_SET_USERDATA_PLACE_HOLDER (CPU_CMD_MASK_CAPTURE | 0x0021) - - -/* Description: - In[0] Task Handle - return parameter: - Out[0] Reserved - Out[1] Video PTS bit[32:2] of last output video frame. - Out[2] Video PTS bit[ 1:0] of last output video frame. - Out[3] Hardware Video PTS counter bit[31:0], - these bits get incremented on every 90kHz clock tick. - Out[4] Hardware Video PTS counter bit32, - these bits get incremented on every 90kHz clock tick. - ReturnCode */ -#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022) - -/* Description: Set VFC parameters - IN[0] - task handle - IN[1] - VFC enable flag, 1 - enable, 0 - disable -*/ -#define CX18_CPU_SET_VFC_PARAM (CPU_CMD_MASK_CAPTURE | 0x0023) - -/* Below is the list of commands related to the data exchange */ -#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000) - -/* Description: This command provides the physical base address of the local - DDR as viewed by EPU - IN[0] - Physical offset where EPU has the local DDR mapped - ReturnCode - One of the ERR_DE_... */ -#define CPU_CMD_DE_SetBase (CPU_CMD_MASK_DE | 0x0001) - -/* Description: This command provides the offsets in the device memory where - the 2 cx18_mdl_ack blocks reside - IN[0] - Task handle. Handle of the task to start - IN[1] - Offset of the first cx18_mdl_ack from the beginning of the - local DDR. - IN[2] - Offset of the second cx18_mdl_ack from the beginning of the - local DDR. - ReturnCode - One of the ERR_DE_... */ -#define CX18_CPU_DE_SET_MDL_ACK (CPU_CMD_MASK_DE | 0x0002) - -/* Description: This command provides the offset to a Memory Descriptor List - IN[0] - Task handle. Handle of the task to start - IN[1] - Offset of the MDL from the beginning of the local DDR. - IN[2] - Number of cx18_mdl_ent structures in the array pointed to by IN[1] - IN[3] - Buffer ID - IN[4] - Total buffer length - ReturnCode - One of the ERR_DE_... */ -#define CX18_CPU_DE_SET_MDL (CPU_CMD_MASK_DE | 0x0005) - -/* Description: This command requests return of all current Memory - Descriptor Lists to the driver - IN[0] - Task handle. Handle of the task to start - ReturnCode - One of the ERR_DE_... */ -#define CX18_CPU_DE_RELEASE_MDL (CPU_CMD_MASK_DE | 0x0006) - -/* Description: This command signals the cpu that the dat buffer has been - consumed and ready for re-use. - IN[0] - Task handle. Handle of the task - IN[1] - Offset of the data block from the beginning of the local DDR. - IN[2] - Number of bytes in the data block - ReturnCode - One of the ERR_DE_... */ -/* #define CX18_CPU_DE_RELEASE_BUFFER (CPU_CMD_MASK_DE | 0x0007) */ - -/* No Error / Success */ -#define CNXT_OK 0x000000 - -/* Received unknown command */ -#define CXERR_UNK_CMD 0x000001 - -/* First parameter in the command is invalid */ -#define CXERR_INVALID_PARAM1 0x000002 - -/* Second parameter in the command is invalid */ -#define CXERR_INVALID_PARAM2 0x000003 - -/* Device interface is not open/found */ -#define CXERR_DEV_NOT_FOUND 0x000004 - -/* Requested function is not implemented/available */ -#define CXERR_NOTSUPPORTED 0x000005 - -/* Invalid pointer is provided */ -#define CXERR_BADPTR 0x000006 - -/* Unable to allocate memory */ -#define CXERR_NOMEM 0x000007 - -/* Object/Link not found */ -#define CXERR_LINK 0x000008 - -/* Device busy, command cannot be executed */ -#define CXERR_BUSY 0x000009 - -/* File/device/handle is not open. */ -#define CXERR_NOT_OPEN 0x00000A - -/* Value is out of range */ -#define CXERR_OUTOFRANGE 0x00000B - -/* Buffer overflow */ -#define CXERR_OVERFLOW 0x00000C - -/* Version mismatch */ -#define CXERR_BADVER 0x00000D - -/* Operation timed out */ -#define CXERR_TIMEOUT 0x00000E - -/* Operation aborted */ -#define CXERR_ABORT 0x00000F - -/* Specified I2C device not found for read/write */ -#define CXERR_I2CDEV_NOTFOUND 0x000010 - -/* Error in I2C data xfer (but I2C device is present) */ -#define CXERR_I2CDEV_XFERERR 0x000011 - -/* Chanel changing component not ready */ -#define CXERR_CHANNELNOTREADY 0x000012 - -/* PPU (Presensation/Decoder) mail box is corrupted */ -#define CXERR_PPU_MB_CORRUPT 0x000013 - -/* CPU (Capture/Encoder) mail box is corrupted */ -#define CXERR_CPU_MB_CORRUPT 0x000014 - -/* APU (Audio) mail box is corrupted */ -#define CXERR_APU_MB_CORRUPT 0x000015 - -/* Unable to open file for reading */ -#define CXERR_FILE_OPEN_READ 0x000016 - -/* Unable to open file for writing */ -#define CXERR_FILE_OPEN_WRITE 0x000017 - -/* Unable to find the I2C section specified */ -#define CXERR_I2C_BADSECTION 0x000018 - -/* Error in I2C data xfer (but I2C device is present) */ -#define CXERR_I2CDEV_DATALOW 0x000019 - -/* Error in I2C data xfer (but I2C device is present) */ -#define CXERR_I2CDEV_CLOCKLOW 0x00001A - -/* No Interrupt received from HW (for I2C access) */ -#define CXERR_NO_HW_I2C_INTR 0x00001B - -/* RPU is not ready to accept commands! */ -#define CXERR_RPU_NOT_READY 0x00001C - -/* RPU is not ready to accept commands! */ -#define CXERR_RPU_NO_ACK 0x00001D - -/* The are no buffers ready. Try again soon! */ -#define CXERR_NODATA_AGAIN 0x00001E - -/* The stream is stopping. Function not allowed now! */ -#define CXERR_STOPPING_STATUS 0x00001F - -/* Trying to access hardware when the power is turned OFF */ -#define CXERR_DEVPOWER_OFF 0x000020 - -#endif /* CX23418_H */ |