diff options
Diffstat (limited to 'drivers/media/video/em28xx')
| -rw-r--r-- | drivers/media/video/em28xx/Kconfig | 40 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/Makefile | 14 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/em28xx-audio.c | 511 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/em28xx-cards.c | 1800 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/em28xx-core.c | 726 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/em28xx-dvb.c | 519 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/em28xx-i2c.c | 614 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/em28xx-input.c | 218 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/em28xx-reg.h | 89 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/em28xx-video.c | 2301 | ||||
| -rw-r--r-- | drivers/media/video/em28xx/em28xx.h | 646 |
11 files changed, 0 insertions, 7478 deletions
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig deleted file mode 100644 index 16a5af30e9d..00000000000 --- a/drivers/media/video/em28xx/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -config VIDEO_EM28XX - tristate "Empia EM28xx USB video capture support" - depends on VIDEO_DEV && I2C && INPUT - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_IR - select VIDEOBUF_VMALLOC - select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO - select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO - ---help--- - This is a video4linux driver for Empia 28xx based TV cards. - - To compile this driver as a module, choose M here: the - module will be called em28xx - -config VIDEO_EM28XX_ALSA - depends on VIDEO_EM28XX && SND - select SND_PCM - tristate "Empia EM28xx ALSA audio module" - ---help--- - This is an ALSA driver for some Empia 28xx based TV cards. - - This is not required for em2800/em2820/em2821 boards. However, - newer em28xx devices uses Vendor Class for audio, instead of - implementing the USB Audio Class. For those chips, this module - will enable digital audio. - - To compile this driver as a module, choose M here: the - module will be called em28xx-alsa - -config VIDEO_EM28XX_DVB - tristate "DVB/ATSC Support for em28xx based TV cards" - depends on VIDEO_EM28XX && DVB_CORE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_ZL10353 if !DVB_FE_CUSTOMISE - select VIDEOBUF_DVB - ---help--- - This adds support for DVB cards based on the - Empiatech em28xx chips. diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile deleted file mode 100644 index 8137a8c94bf..00000000000 --- a/drivers/media/video/em28xx/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -em28xx-objs := em28xx-video.o em28xx-i2c.o em28xx-cards.o em28xx-core.o \ - em28xx-input.o - -em28xx-alsa-objs := em28xx-audio.o - -obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o -obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o -obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o - -EXTRA_CFLAGS += -Idrivers/media/video -EXTRA_CFLAGS += -Idrivers/media/common/tuners -EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends - diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c deleted file mode 100644 index 3c006103c1e..00000000000 --- a/drivers/media/video/em28xx/em28xx-audio.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Empiatech em28x1 audio extension - * - * Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com> - * - * Copyright (C) 2007 Mauro Carvalho Chehab <mchehab@infradead.org> - * - Port to work with the in-kernel driver - * - Several cleanups - * - * This driver is based on my previous au600 usb pstn audio driver - * and inherits all the copyrights - * - * 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 <linux/kernel.h> -#include <linux/usb.h> -#include <linux/init.h> -#include <linux/sound.h> -#include <linux/spinlock.h> -#include <linux/soundcard.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/proc_fs.h> -#include <linux/module.h> -#include <sound/core.h> -#include <sound/pcm.h> -#include <sound/pcm_params.h> -#include <sound/info.h> -#include <sound/initval.h> -#include <sound/control.h> -#include <media/v4l2-common.h> -#include "em28xx.h" - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "activates debug info"); - -#define dprintk(fmt, arg...) do { \ - if (debug) \ - printk(KERN_INFO "em28xx-audio %s: " fmt, \ - __func__, ##arg); \ - } while (0) - -static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; - -static int em28xx_isoc_audio_deinit(struct em28xx *dev) -{ - int i; - - dprintk("Stopping isoc\n"); - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - usb_kill_urb(dev->adev->urb[i]); - usb_free_urb(dev->adev->urb[i]); - dev->adev->urb[i] = NULL; - } - - return 0; -} - -static void em28xx_audio_isocirq(struct urb *urb) -{ - struct em28xx *dev = urb->context; - int i; - unsigned int oldptr; - unsigned long flags; - int period_elapsed = 0; - int status; - unsigned char *cp; - unsigned int stride; - struct snd_pcm_substream *substream; - struct snd_pcm_runtime *runtime; - if (dev->adev->capture_pcm_substream) { - substream = dev->adev->capture_pcm_substream; - runtime = substream->runtime; - stride = runtime->frame_bits >> 3; - - for (i = 0; i < urb->number_of_packets; i++) { - int length = - urb->iso_frame_desc[i].actual_length / stride; - cp = (unsigned char *)urb->transfer_buffer + - urb->iso_frame_desc[i].offset; - - if (!length) - continue; - - spin_lock_irqsave(&dev->adev->slock, flags); - - oldptr = dev->adev->hwptr_done_capture; - dev->adev->hwptr_done_capture += length; - if (dev->adev->hwptr_done_capture >= - runtime->buffer_size) - dev->adev->hwptr_done_capture -= - runtime->buffer_size; - - dev->adev->capture_transfer_done += length; - if (dev->adev->capture_transfer_done >= - runtime->period_size) { - dev->adev->capture_transfer_done -= - runtime->period_size; - period_elapsed = 1; - } - - spin_unlock_irqrestore(&dev->adev->slock, flags); - - if (oldptr + length >= runtime->buffer_size) { - unsigned int cnt = - runtime->buffer_size - oldptr - 1; - memcpy(runtime->dma_area + oldptr * stride, cp, - cnt * stride); - memcpy(runtime->dma_area, cp + cnt, - length * stride - cnt * stride); - } else { - memcpy(runtime->dma_area + oldptr * stride, cp, - length * stride); - } - } - if (period_elapsed) - snd_pcm_period_elapsed(substream); - } - urb->status = 0; - - if (dev->adev->shutdown) - return; - - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status < 0) { - em28xx_errdev("resubmit of audio urb failed (error=%i)\n", - status); - } - return; -} - -static int em28xx_init_audio_isoc(struct em28xx *dev) -{ - int i, errCode; - const int sb_size = EM28XX_NUM_AUDIO_PACKETS * - EM28XX_AUDIO_MAX_PACKET_SIZE; - - dprintk("Starting isoc transfers\n"); - - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - struct urb *urb; - int j, k; - - dev->adev->transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC); - if (!dev->adev->transfer_buffer[i]) - return -ENOMEM; - - memset(dev->adev->transfer_buffer[i], 0x80, sb_size); - urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); - if (!urb) - return -ENOMEM; - - urb->dev = dev->udev; - urb->context = dev; - urb->pipe = usb_rcvisocpipe(dev->udev, 0x83); - urb->transfer_flags = URB_ISO_ASAP; - urb->transfer_buffer = dev->adev->transfer_buffer[i]; - urb->interval = 1; - urb->complete = em28xx_audio_isocirq; - urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS; - urb->transfer_buffer_length = sb_size; - - for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS; - j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - EM28XX_AUDIO_MAX_PACKET_SIZE; - } - dev->adev->urb[i] = urb; - } - - for (i = 0; i < EM28XX_AUDIO_BUFS; i++) { - errCode = usb_submit_urb(dev->adev->urb[i], GFP_ATOMIC); - if (errCode) { - em28xx_isoc_audio_deinit(dev); - - return errCode; - } - } - - return 0; -} - -static int em28xx_cmd(struct em28xx *dev, int cmd, int arg) -{ - dprintk("%s transfer\n", (dev->adev->capture_stream == STREAM_ON)? - "stop" : "start"); - - switch (cmd) { - case EM28XX_CAPTURE_STREAM_EN: - if (dev->adev->capture_stream == STREAM_OFF && arg == 1) { - dev->adev->capture_stream = STREAM_ON; - em28xx_init_audio_isoc(dev); - } else if (dev->adev->capture_stream == STREAM_ON && arg == 0) { - dev->adev->capture_stream = STREAM_OFF; - em28xx_isoc_audio_deinit(dev); - } else { - printk(KERN_ERR "An underrun very likely occurred. " - "Ignoring it.\n"); - } - return 0; - default: - return -EINVAL; - } -} - -static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, - size_t size) -{ - struct snd_pcm_runtime *runtime = subs->runtime; - - dprintk("Alocating 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 struct snd_pcm_hardware snd_em28xx_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_CONTINUOUS | SNDRV_PCM_RATE_KNOT, - - .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, */ -}; - -static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - struct snd_pcm_runtime *runtime = substream->runtime; - int ret = 0; - - dprintk("opening device and trying to acquire exclusive lock\n"); - - if (!dev) { - printk(KERN_ERR "BUG: em28xx can't find device struct." - " Can't proceed with open\n"); - return -ENODEV; - } - - /* Sets volume, mute, etc */ - - dev->mute = 0; - mutex_lock(&dev->lock); - ret = em28xx_audio_analog_set(dev); - mutex_unlock(&dev->lock); - if (ret < 0) - goto err; - - runtime->hw = snd_em28xx_hw_capture; - if (dev->alt == 0 && dev->adev->users == 0) { - int errCode; - dev->alt = 7; - errCode = usb_set_interface(dev->udev, 0, 7); - dprintk("changing alternate number to 7\n"); - } - - dev->adev->users++; - - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - dev->adev->capture_pcm_substream = substream; - runtime->private_data = dev; - - return 0; -err: - printk(KERN_ERR "Error while configuring em28xx mixer\n"); - return ret; -} - -static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - dev->adev->users--; - - dprintk("closing device\n"); - - dev->mute = 1; - mutex_lock(&dev->lock); - em28xx_audio_analog_set(dev); - mutex_unlock(&dev->lock); - - if (dev->adev->users == 0 && dev->adev->shutdown == 1) { - dprintk("audio users: %d\n", dev->adev->users); - dprintk("disabling audio stream!\n"); - dev->adev->shutdown = 0; - dprintk("released lock\n"); - em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); - } - return 0; -} - -static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - unsigned int channels, rate, format; - int ret; - - dprintk("Setting capture parameters\n"); - - ret = snd_pcm_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - format = params_format(hw_params); - rate = params_rate(hw_params); - channels = params_channels(hw_params); - - /* TODO: set up em28xx audio chip to deliver the correct audio format, - current default is 48000hz multiplexed => 96000hz mono - which shouldn't matter since analogue TV only supports mono */ - return 0; -} - -static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - - dprintk("Stop capture, if needed\n"); - - if (dev->adev->capture_stream == STREAM_ON) - em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 0); - - return 0; -} - -static int snd_em28xx_prepare(struct snd_pcm_substream *substream) -{ - return 0; -} - -static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct em28xx *dev = snd_pcm_substream_chip(substream); - - dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START)? - "start": "stop"); - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, 1); - return 0; - case SNDRV_PCM_TRIGGER_STOP: - dev->adev->shutdown = 1; - return 0; - default: - return -EINVAL; - } -} - -static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream - *substream) -{ - struct em28xx *dev; - - snd_pcm_uframes_t hwptr_done; - dev = snd_pcm_substream_chip(substream); - hwptr_done = dev->adev->hwptr_done_capture; - - 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_em28xx_pcm_capture = { - .open = snd_em28xx_capture_open, - .close = snd_em28xx_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_em28xx_hw_capture_params, - .hw_free = snd_em28xx_hw_capture_free, - .prepare = snd_em28xx_prepare, - .trigger = snd_em28xx_capture_trigger, - .pointer = snd_em28xx_capture_pointer, - .page = snd_pcm_get_vmalloc_page, -}; - -static int em28xx_audio_init(struct em28xx *dev) -{ - struct em28xx_audio *adev; - struct snd_pcm *pcm; - struct snd_card *card; - static int devnr; - int ret, err; - - if (dev->has_audio_class) { - /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module */ - return 0; - } - - printk(KERN_INFO "em28xx-audio.c: probing for em28x1 " - "non standard usbaudio\n"); - printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " - "Rechberger\n"); - - adev = kzalloc(sizeof(*adev), GFP_KERNEL); - if (!adev) { - printk(KERN_ERR "em28xx-audio.c: out of memory\n"); - return -1; - } - card = snd_card_new(index[devnr], "Em28xx Audio", THIS_MODULE, 0); - if (card == NULL) { - kfree(adev); - return -ENOMEM; - } - - spin_lock_init(&adev->slock); - ret = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); - pcm->info_flags = 0; - pcm->private_data = dev; - strcpy(pcm->name, "Empia 28xx Capture"); - strcpy(card->driver, "Empia Em28xx Audio"); - strcpy(card->shortname, "Em28xx Audio"); - strcpy(card->longname, "Empia Em28xx Audio"); - - err = snd_card_register(card); - if (err < 0) { - snd_card_free(card); - return -ENOMEM; - } - adev->sndcard = card; - adev->udev = dev->udev; - dev->adev = adev; - - return 0; -} - -static int em28xx_audio_fini(struct em28xx *dev) -{ - if (dev == NULL) - return 0; - - if (dev->has_audio_class) { - /* This device does not support the extension (in this case - the device is expecting the snd-usb-audio module */ - return 0; - } - - if (dev->adev) { - snd_card_free(dev->adev->sndcard); - kfree(dev->adev); - dev->adev = NULL; - } - - return 0; -} - -static struct em28xx_ops audio_ops = { - .id = EM28XX_AUDIO, - .name = "Em28xx Audio Extension", - .init = em28xx_audio_init, - .fini = em28xx_audio_fini, -}; - -static int __init em28xx_alsa_register(void) -{ - return em28xx_register_extension(&audio_ops); -} - -static void __exit em28xx_alsa_unregister(void) -{ - em28xx_unregister_extension(&audio_ops); -} - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); -MODULE_DESCRIPTION("Em28xx Audio driver"); - -module_init(em28xx_alsa_register); -module_exit(em28xx_alsa_unregister); diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c deleted file mode 100644 index 476ae44a62d..00000000000 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ /dev/null @@ -1,1800 +0,0 @@ -/* - em28xx-cards.c - driver for Empia EM2800/EM2820/2840 USB - video capture devices - - Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> - Markus Rechberger <mrechberger@gmail.com> - Mauro Carvalho Chehab <mchehab@infradead.org> - Sascha Sommer <saschasommer@freenet.de> - - 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 <linux/init.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/i2c.h> -#include <linux/usb.h> -#include <media/tuner.h> -#include <media/msp3400.h> -#include <media/saa7115.h> -#include <media/tvp5150.h> -#include <media/tveeprom.h> -#include <media/v4l2-common.h> -#include <media/v4l2-chip-ident.h> - -#include "em28xx.h" - -static int tuner = -1; -module_param(tuner, int, 0444); -MODULE_PARM_DESC(tuner, "tuner type"); - -static unsigned int disable_ir; -module_param(disable_ir, int, 0444); -MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); - -struct em28xx_hash_table { - unsigned long hash; - unsigned int model; - unsigned int tuner; -}; - -struct em28xx_board em28xx_boards[] = { - [EM2750_BOARD_UNKNOWN] = { - .name = "Unknown EM2750/EM2751 webcam grabber", - .vchannels = 1, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = 0, - .amux = 0, - } }, - }, - [EM2800_BOARD_UNKNOWN] = { - .name = "Unknown EM2800 video grabber", - .is_em2800 = 1, - .vchannels = 2, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_UNKNOWN] = { - .name = "Unknown EM2750/28xx video grabber", - .is_em2800 = 0, - .tuner_type = TUNER_ABSENT, - }, - [EM2750_BOARD_DLCW_130] = { - /* Beijing Huaqi Information Digital Technology Co., Ltd */ - .name = "Huaqi DLCW-130", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 1, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = 0, - .amux = 0, - } }, - }, - [EM2800_BOARD_KWORLD_USB2800] = { - .name = "Kworld USB2800", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .is_em2800 = 1, - .vchannels = 3, - .tuner_type = TUNER_PHILIPS_FCV1236D, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_KWORLD_PVRTV2800RF] = { - .name = "Kworld PVR TV 2800 RF", - .is_em2800 = 0, - .vchannels = 2, - .tuner_type = TUNER_TEMIC_PAL, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_TERRATEC_CINERGY_250] = { - .name = "Terratec Cinergy 250 USB", - .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 1, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_PINNACLE_USB_2] = { - .name = "Pinnacle PCTV USB 2", - .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_HAUPPAUGE_WINTV_USB_2] = { - .name = "Hauppauge WinTV USB 2", - .vchannels = 3, - .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE| - TDA9887_PORT2_ACTIVE, - .decoder = EM28XX_TVP5150, - .has_msp34xx = 1, - /*FIXME: S-Video not tested */ - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = MSP_INPUT_DEFAULT, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = MSP_INPUT(MSP_IN_SCART1, MSP_IN_TUNER1, - MSP_DSP_IN_SCART, MSP_DSP_IN_SCART), - } }, - }, - [EM2820_BOARD_DLINK_USB_TV] = { - .name = "D-Link DUB-T210 TV Tuner", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .is_em2800 = 0, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 1, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_HERCULES_SMART_TV_USB2] = { - .name = "Hercules Smart TV USB 2.0", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 1, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_PINNACLE_USB_2_FM1216ME] = { - .name = "Pinnacle PCTV USB 2 (Philips FM1216ME)", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .is_em2800 = 0, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_GADMEI_UTV310] = { - .name = "Gadmei UTV310", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_TNF_5335MF, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE] = { - .name = "Leadtek Winfast USB II Deluxe", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7114, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = 2, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = 0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = 9, - .amux = 1, - } }, - }, - [EM2820_BOARD_PINNACLE_DVC_100] = { - .name = "Pinnacle Dazzle DVC 100", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = { - .name = "Videology 20K14XUSB USB2.0", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 1, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = 0, - .amux = 0, - } }, - }, - [EM2821_BOARD_PROLINK_PLAYTV_USB2] = { - .name = "SIIG AVTuner-PVR/Prolink PlayTV USB 2.0", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .is_em2800 = 0, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, /* unknown? */ - .tda9887_conf = TDA9887_PRESENT, /* unknown? */ - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 1, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2821_BOARD_SUPERCOMP_USB_2] = { - .name = "Supercomp USB 2.0 TV", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .is_em2800 = 0, - .tuner_type = TUNER_PHILIPS_FM1236_MK3, - .tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 1, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2821_BOARD_USBGEAR_VD204] = { - .name = "Usbgear VD204v9", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 2, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2860_BOARD_NETGMBH_CAM] = { - /* Beijing Huaqi Information Digital Technology Co., Ltd */ - .name = "NetGMBH Cam", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 1, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = 0, - .amux = 0, - } }, - }, - [EM2860_BOARD_TYPHOON_DVD_MAKER] = { - .name = "Typhoon DVD Maker", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 2, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2860_BOARD_GADMEI_UTV330] = { - .name = "Gadmei UTV330", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_TNF_5335MF, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2860_BOARD_TERRATEC_HYBRID_XS] = { - .name = "Terratec Cinergy A Hybrid XS", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2861_BOARD_KWORLD_PVRTV_300U] = { - .name = "KWorld PVRTV 300U", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2861_BOARD_YAKUMO_MOVIE_MIXER] = { - .name = "Yakumo MovieMixer", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2861_BOARD_PLEXTOR_PX_TV100U] = { - .name = "Plextor ConvertX PX-TV100U", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_TNF_5335MF, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2870_BOARD_TERRATEC_XS] = { - .name = "Terratec Cinergy T XS", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_XC2028, - }, - [EM2870_BOARD_TERRATEC_XS_MT2060] = { - .name = "Terratec Cinergy T XS (MT2060)", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_ABSENT, /* MT2060 */ - }, - [EM2870_BOARD_KWORLD_350U] = { - .name = "Kworld 350 U DVB-T", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_XC2028, - }, - [EM2870_BOARD_KWORLD_355U] = { - .name = "Kworld 355 U DVB-T", - .valid = EM28XX_BOARD_NOT_VALIDATED, - }, - [EM2870_BOARD_PINNACLE_PCTV_DVB] = { - .name = "Pinnacle PCTV DVB-T", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_ABSENT, /* MT2060 */ - }, - [EM2870_BOARD_COMPRO_VIDEOMATE] = { - .name = "Compro, VideoMate U3", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .tuner_type = TUNER_ABSENT, /* MT2060 */ - }, - [EM2880_BOARD_TERRATEC_HYBRID_XS_FR] = { - .name = "Terratec Hybrid XS Secam", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .has_msp34xx = 1, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { - .name = "Hauppauge WinTV HVR 900", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .has_dvb = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2] = { - .name = "Hauppauge WinTV HVR 900 (R2)", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { - .name = "Hauppauge WinTV HVR 950", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .has_12mhz_i2s = 1, - .has_dvb = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2880_BOARD_PINNACLE_PCTV_HD_PRO] = { - .name = "Pinnacle PCTV HD Pro Stick", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .has_12mhz_i2s = 1, - .has_dvb = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { - .name = "AMD ATI TV Wonder HD 600", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .mts_firmware = 1, - .has_12mhz_i2s = 1, - .has_dvb = 1, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2880_BOARD_TERRATEC_HYBRID_XS] = { - .name = "Terratec Hybrid XS", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .has_dvb = 1, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - /* maybe there's a reason behind it why Terratec sells the Hybrid XS - as Prodigy XS with a different PID, let's keep it separated for now - maybe we'll need it lateron */ - [EM2880_BOARD_TERRATEC_PRODIGY_XS] = { - .name = "Terratec Prodigy XS", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2820_BOARD_MSI_VOX_USB_2] = { - .name = "MSI VOX USB 2.0", - .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT | - TDA9887_PORT1_ACTIVE | - TDA9887_PORT2_ACTIVE, - .max_range_640_480 = 1, - - .decoder = EM28XX_SAA7114, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE4, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2800_BOARD_TERRATEC_CINERGY_200] = { - .name = "Terratec Cinergy 200 USB", - .is_em2800 = 1, - .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2800_BOARD_GRABBEEX_USB2800] = { - .name = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder", - .is_em2800 = 1, - .vchannels = 2, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2800_BOARD_LEADTEK_WINFAST_USBII] = { - .name = "Leadtek Winfast USB II", - .is_em2800 = 1, - .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2800_BOARD_KWORLD_USB2800] = { - .name = "Kworld USB2800", - .is_em2800 = 1, - .vchannels = 3, - .tuner_type = TUNER_PHILIPS_FCV1236D, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_PINNACLE_DVC_90] = { - .name = "Pinnacle Dazzle DVC 90/DVC 100", - .vchannels = 3, - .tuner_type = TUNER_ABSENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2800_BOARD_VGEAR_POCKETTV] = { - .name = "V-Gear PocketTV", - .is_em2800 = 1, - .vchannels = 3, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 1, - } }, - }, - [EM2820_BOARD_PROLINK_PLAYTV_USB2] = { - .name = "Pixelview Prolink PlayTV USB 2.0", - .vchannels = 3, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_YMEC_TVF_5533MF, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = SAA7115_COMPOSITE2, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = SAA7115_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, - [EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA] = { - .name = "PointNix Intra-Oral Camera", - .has_snapshot_button = 1, - .vchannels = 1, - .tda9887_conf = TDA9887_PRESENT, - .tuner_type = TUNER_ABSENT, - .decoder = EM28XX_SAA7113, - .input = { { - .type = EM28XX_VMUX_SVIDEO, - .vmux = SAA7115_SVIDEO3, - .amux = 0, - } }, - }, - [EM2880_BOARD_MSI_DIGIVOX_AD] = { - .name = "MSI DigiVox A/D", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2880_BOARD_MSI_DIGIVOX_AD_II] = { - .name = "MSI DigiVox A/D II", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2880_BOARD_KWORLD_DVB_305U] = { - .name = "KWorld DVB-T 305U", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2880_BOARD_KWORLD_DVB_310U] = { - .name = "KWorld DVB-T 310U", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2881_BOARD_DNT_DA2_HYBRID] = { - .name = "DNT DA2 Hybrid", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2881_BOARD_PINNACLE_HYBRID_PRO] = { - .name = "Pinnacle Hybrid Pro", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2882_BOARD_PINNACLE_HYBRID_PRO] = { - .name = "Pinnacle Hybrid Pro (2)", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2882_BOARD_KWORLD_VS_DVBT] = { - .name = "Kworld VS-DVB-T 323UR", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2882_BOARD_TERRATEC_HYBRID_XS] = { - .name = "Terratec Hybrid XS (em2882)", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2883_BOARD_KWORLD_HYBRID_A316] = { - .name = "Kworld PlusTV HD Hybrid 330", - .valid = EM28XX_BOARD_NOT_VALIDATED, - .vchannels = 3, - .is_em2800 = 0, - .tuner_type = TUNER_XC2028, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = 0, - }, { - .type = EM28XX_VMUX_COMPOSITE1, - .vmux = TVP5150_COMPOSITE1, - .amux = 1, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = 1, - } }, - }, - [EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = { - .name = "Compro VideoMate ForYou/Stereo", - .vchannels = 2, - .tuner_type = TUNER_LG_PAL_NEW_TAPC, - .tda9887_conf = TDA9887_PRESENT, - .decoder = EM28XX_TVP5150, - .input = { { - .type = EM28XX_VMUX_TELEVISION, - .vmux = TVP5150_COMPOSITE0, - .amux = EM28XX_AMUX_LINE_IN, - }, { - .type = EM28XX_VMUX_SVIDEO, - .vmux = TVP5150_SVIDEO, - .amux = EM28XX_AMUX_LINE_IN, - } }, - }, -}; -const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); - -/* table of devices that work with this driver */ -struct usb_device_id em28xx_id_table [] = { - { USB_DEVICE(0xeb1a, 0x2750), - .driver_info = EM2750_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2751), - .driver_info = EM2750_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2800), - .driver_info = EM2800_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2820), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2821), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2860), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2861), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2870), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2881), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0x2883), - .driver_info = EM2820_BOARD_UNKNOWN }, - { USB_DEVICE(0xeb1a, 0xe300), - .driver_info = EM2861_BOARD_KWORLD_PVRTV_300U }, - { USB_DEVICE(0xeb1a, 0xe305), - .driver_info = EM2880_BOARD_KWORLD_DVB_305U }, - { USB_DEVICE(0xeb1a, 0xe310), - .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD }, - { USB_DEVICE(0xeb1a, 0xa316), - .driver_info = EM2883_BOARD_KWORLD_HYBRID_A316 }, - { USB_DEVICE(0xeb1a, 0xe320), - .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD_II }, - { USB_DEVICE(0xeb1a, 0xe323), - .driver_info = EM2882_BOARD_KWORLD_VS_DVBT }, - { USB_DEVICE(0xeb1a, 0xe350), - .driver_info = EM2870_BOARD_KWORLD_350U }, - { USB_DEVICE(0xeb1a, 0xe355), - .driver_info = EM2870_BOARD_KWORLD_355U }, - { USB_DEVICE(0xeb1a, 0x2801), - .driver_info = EM2800_BOARD_GRABBEEX_USB2800 }, - { USB_DEVICE(0xeb1a, 0xe357), - .driver_info = EM2870_BOARD_KWORLD_355U }, - { USB_DEVICE(0x0ccd, 0x0036), - .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, - { USB_DEVICE(0x0ccd, 0x004c), - .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS_FR }, - { USB_DEVICE(0x0ccd, 0x004f), - .driver_info = EM2860_BOARD_TERRATEC_HYBRID_XS }, - { USB_DEVICE(0x0ccd, 0x005e), - .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, - { USB_DEVICE(0x0ccd, 0x0042), - .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, - { USB_DEVICE(0x0ccd, 0x0043), - .driver_info = EM2870_BOARD_TERRATEC_XS }, - { USB_DEVICE(0x0ccd, 0x0047), - .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, - { USB_DEVICE(0x185b, 0x2870), - .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE }, - { USB_DEVICE(0x185b, 0x2041), - .driver_info = EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU }, - { USB_DEVICE(0x2040, 0x4200), - .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, - { USB_DEVICE(0x2040, 0x4201), - .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, - { USB_DEVICE(0x2040, 0x6500), - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, - { USB_DEVICE(0x2040, 0x6502), - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 }, - { USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */ - .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x2040, 0x6517), /* HP HVR-950 */ - .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x2040, 0x651b), /* RP HVR-950 */ - .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */ - .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x0438, 0xb002), - .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, - { USB_DEVICE(0x2001, 0xf112), - .driver_info = EM2820_BOARD_DLINK_USB_TV }, - { USB_DEVICE(0x2304, 0x0207), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, - { USB_DEVICE(0x2304, 0x0208), - .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, - { USB_DEVICE(0x2304, 0x021a), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, - { USB_DEVICE(0x2304, 0x0226), - .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO }, - { USB_DEVICE(0x2304, 0x0227), - .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, - { USB_DEVICE(0x0413, 0x6023), - .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, - { USB_DEVICE(0x093b, 0xa005), - .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U }, - { }, -}; -MODULE_DEVICE_TABLE(usb, em28xx_id_table); - -/* - * Reset sequences for analog/digital modes - */ - -/* Reset for the most [analog] boards */ -static struct em28xx_reg_seq default_analog[] = { - {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Reset for the most [digital] boards */ -static struct em28xx_reg_seq default_digital[] = { - {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Board Hauppauge WinTV HVR 900 analog */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { - {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10}, - {0x05, 0xff, 0x10, 10}, - { -1, -1, -1, -1}, -}; - -/* Board Hauppauge WinTV HVR 900 digital */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { - {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10}, - {EM2880_R04_GPO, 0x04, 0x0f, 10}, - {EM2880_R04_GPO, 0x0c, 0x0f, 10}, - { -1, -1, -1, -1}, -}; - -/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ -static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { - {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ -static struct em28xx_reg_seq em2880_msi_digivox_ad_digital[] = { - {EM28XX_R08_GPIO, 0x6a, ~EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Board - EM2870 Kworld 355u - Analog - No input analog */ -static struct em28xx_reg_seq em2870_kworld_355u_digital[] = { - {EM2880_R04_GPO, 0x01, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -/* Callback for the most boards */ -static struct em28xx_reg_seq default_callback[] = { - {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, - {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10}, - {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, - { -1, -1, -1, -1}, -}; - -/* Callback for EM2882 TERRATEC HYBRID XS */ -static struct em28xx_reg_seq em2882_terratec_hybrid_xs_digital[] = { - {EM28XX_R08_GPIO, 0x2e, 0xff, 6}, - {EM28XX_R08_GPIO, 0x3e, ~EM_GPIO_4, 6}, - {EM2880_R04_GPO, 0x04, 0xff, 10}, - {EM2880_R04_GPO, 0x0c, 0xff, 10}, - { -1, -1, -1, -1}, -}; - -/* - * EEPROM hash table for devices with generic USB IDs - */ -static struct em28xx_hash_table em28xx_eeprom_hash [] = { - /* P/N: SA 60002070465 Tuner: TVF7533-MF */ - {0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF}, -}; - -/* I2C devicelist hash table for devices with generic USB IDs */ -static struct em28xx_hash_table em28xx_i2c_hash[] = { - {0xb06a32c3, EM2800_BOARD_TERRATEC_CINERGY_200, TUNER_LG_PAL_NEW_TAPC}, - {0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC}, - {0x1ba50080, EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA, TUNER_ABSENT}, -}; - -int em28xx_tuner_callback(void *ptr, int command, int arg) -{ - int rc = 0; - struct em28xx *dev = ptr; - - if (dev->tuner_type != TUNER_XC2028) - return 0; - - if (command != XC2028_TUNER_RESET) - return 0; - - if (dev->mode == EM28XX_ANALOG_MODE) - rc = em28xx_gpio_set(dev, dev->tun_analog_gpio); - else - rc = em28xx_gpio_set(dev, dev->tun_digital_gpio); - - return rc; -} -EXPORT_SYMBOL_GPL(em28xx_tuner_callback); - -static void em28xx_set_model(struct em28xx *dev) -{ - dev->is_em2800 = em28xx_boards[dev->model].is_em2800; - dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx; - dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf; - dev->decoder = em28xx_boards[dev->model].decoder; - dev->video_inputs = em28xx_boards[dev->model].vchannels; - dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s; - dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; - dev->has_dvb = em28xx_boards[dev->model].has_dvb; - dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button; - dev->valid = em28xx_boards[dev->model].valid; -} - -/* Since em28xx_pre_card_setup() requires a proper dev->model, - * this won't work for boards with generic PCI IDs - */ -void em28xx_pre_card_setup(struct em28xx *dev) -{ - int rc; - - rc = em28xx_read_reg(dev, EM2880_R04_GPO); - if (rc >= 0) - dev->reg_gpo = rc; - - dev->wait_after_write = 5; - rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID); - if (rc > 0) { - switch (rc) { - case CHIP_ID_EM2860: - em28xx_info("chip ID is em2860\n"); - break; - case CHIP_ID_EM2883: - em28xx_info("chip ID is em2882/em2883\n"); - dev->wait_after_write = 0; - break; - default: - em28xx_info("em28xx chip ID = %d\n", rc); - } - } - em28xx_set_model(dev); - - /* request some modules */ - switch (dev->model) { - case EM2880_BOARD_TERRATEC_PRODIGY_XS: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: - case EM2860_BOARD_TERRATEC_HYBRID_XS: - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: - case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: - case EM2882_BOARD_PINNACLE_HYBRID_PRO: - case EM2883_BOARD_KWORLD_HYBRID_A316: - case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - msleep(50); - - /* Sets GPO/GPIO sequences for this device */ - dev->analog_gpio = hauppauge_wintv_hvr_900_analog; - dev->digital_gpio = hauppauge_wintv_hvr_900_digital; - dev->tun_analog_gpio = default_callback; - dev->tun_digital_gpio = default_callback; - break; - - case EM2882_BOARD_TERRATEC_HYBRID_XS: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - msleep(50); - - /* should be added ir_codes here */ - - /* Sets GPO/GPIO sequences for this device */ - dev->analog_gpio = hauppauge_wintv_hvr_900_analog; - dev->digital_gpio = hauppauge_wintv_hvr_900_digital; - dev->tun_analog_gpio = default_callback; - dev->tun_digital_gpio = em2882_terratec_hybrid_xs_digital; - break; - - case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: - case EM2880_BOARD_TERRATEC_HYBRID_XS: - case EM2870_BOARD_TERRATEC_XS: - case EM2881_BOARD_PINNACLE_HYBRID_PRO: - case EM2880_BOARD_KWORLD_DVB_310U: - case EM2870_BOARD_KWORLD_350U: - case EM2881_BOARD_DNT_DA2_HYBRID: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - msleep(50); - - /* NOTE: EM2881_DNT_DA2_HYBRID spend 140 msleep for digital - and analog commands. If this commands doesn't work, - add this timer. */ - - /* Sets GPO/GPIO sequences for this device */ - dev->analog_gpio = default_analog; - dev->digital_gpio = default_digital; - dev->tun_analog_gpio = default_callback; - dev->tun_digital_gpio = default_callback; - break; - - case EM2880_BOARD_MSI_DIGIVOX_AD: - case EM2880_BOARD_MSI_DIGIVOX_AD_II: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - msleep(50); - - /* Sets GPO/GPIO sequences for this device */ - dev->analog_gpio = em2880_msi_digivox_ad_analog; - dev->digital_gpio = em2880_msi_digivox_ad_digital; - dev->tun_analog_gpio = default_callback; - dev->tun_digital_gpio = default_callback; - break; - - case EM2750_BOARD_UNKNOWN: - case EM2750_BOARD_DLCW_130: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x0a", 1); - break; - - case EM2861_BOARD_PLEXTOR_PX_TV100U: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - /* FIXME guess */ - /* Turn on analog audio output */ - em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); - break; - - case EM2861_BOARD_KWORLD_PVRTV_300U: - case EM2880_BOARD_KWORLD_DVB_305U: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x4c", 1); - msleep(10); - em28xx_write_regs(dev, 0x08, "\x6d", 1); - msleep(10); - em28xx_write_regs(dev, 0x08, "\x7d", 1); - msleep(10); - break; - - case EM2870_BOARD_KWORLD_355U: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - msleep(50); - - /* Sets GPO/GPIO sequences for this device */ - dev->digital_gpio = em2870_kworld_355u_digital; - break; - - case EM2870_BOARD_COMPRO_VIDEOMATE: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - /* TODO: someone can do some cleanup here... - not everything's needed */ - em28xx_write_regs(dev, 0x04, "\x00", 1); - msleep(10); - em28xx_write_regs(dev, 0x04, "\x01", 1); - msleep(10); - em28xx_write_regs(dev, 0x08, "\xfd", 1); - mdelay(70); - em28xx_write_regs(dev, 0x08, "\xfc", 1); - mdelay(70); - em28xx_write_regs(dev, 0x08, "\xdc", 1); - mdelay(70); - em28xx_write_regs(dev, 0x08, "\xfc", 1); - mdelay(70); - break; - - case EM2870_BOARD_TERRATEC_XS_MT2060: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - /* this device needs some gpio writes to get the DVB-T - demod work */ - em28xx_write_regs(dev, 0x08, "\xfe", 1); - mdelay(70); - em28xx_write_regs(dev, 0x08, "\xde", 1); - mdelay(70); - dev->em28xx_write_regs(dev, 0x08, "\xfe", 1); - mdelay(70); - break; - - case EM2870_BOARD_PINNACLE_PCTV_DVB: - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - /* this device needs some gpio writes to get the - DVB-T demod work */ - em28xx_write_regs(dev, 0x08, "\xfe", 1); - mdelay(70); - em28xx_write_regs(dev, 0x08, "\xde", 1); - mdelay(70); - em28xx_write_regs(dev, 0x08, "\xfe", 1); - mdelay(70); - /* switch em2880 rc protocol */ - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x22", 1); - /* should be added ir_codes here */ - break; - - case EM2820_BOARD_GADMEI_UTV310: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - /* Turn on analog audio output */ - em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); - break; - - case EM2860_BOARD_GADMEI_UTV330: - /* Turn on IR */ - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - /* should be added ir_codes here */ - break; - - case EM2820_BOARD_MSI_VOX_USB_2: - em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); - em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); - /* enables audio for that device */ - em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); - break; - } - - em28xx_gpio_set(dev, dev->tun_analog_gpio); - em28xx_set_mode(dev, EM28XX_ANALOG_MODE); - - /* Unlock device */ - em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); -} - -static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) -{ - memset(ctl, 0, sizeof(*ctl)); - - ctl->fname = XC2028_DEFAULT_FIRMWARE; - ctl->max_len = 64; - ctl->mts = em28xx_boards[dev->model].mts_firmware; - - switch (dev->model) { - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - ctl->demod = XC3028_FE_ZARLINK456; - break; - case EM2880_BOARD_TERRATEC_HYBRID_XS: - ctl->demod = XC3028_FE_ZARLINK456; - break; - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: - /* djh - Not sure which demod we need here */ - ctl->demod = XC3028_FE_DEFAULT; - break; - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: - case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: - case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: - /* FIXME: Better to specify the needed IF */ - ctl->demod = XC3028_FE_DEFAULT; - break; - default: - ctl->demod = XC3028_FE_OREN538; - } -} - -static void em28xx_config_tuner(struct em28xx *dev) -{ - struct v4l2_priv_tun_config xc2028_cfg; - struct tuner_setup tun_setup; - struct v4l2_frequency f; - - if (dev->tuner_type == TUNER_ABSENT) - return; - - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = dev->tuner_type; - tun_setup.addr = dev->tuner_addr; - tun_setup.tuner_callback = em28xx_tuner_callback; - - em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); - - if (dev->tuner_type == TUNER_XC2028) { - struct xc2028_ctrl ctl; - - em28xx_setup_xc3028(dev, &ctl); - - xc2028_cfg.tuner = TUNER_XC2028; - xc2028_cfg.priv = &ctl; - - em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg); - } - - /* configure tuner */ - f.tuner = 0; - f.type = V4L2_TUNER_ANALOG_TV; - f.frequency = 9076; /* just a magic number */ - dev->ctl_freq = f.frequency; - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); -} - -static int em28xx_hint_board(struct em28xx *dev) -{ - int i; - - /* HINT method: EEPROM - * - * This method works only for boards with eeprom. - * Uses a hash of all eeprom bytes. The hash should be - * unique for a vendor/tuner pair. - * There are a high chance that tuners for different - * video standards produce different hashes. - */ - for (i = 0; i < ARRAY_SIZE(em28xx_eeprom_hash); i++) { - if (dev->hash == em28xx_eeprom_hash[i].hash) { - dev->model = em28xx_eeprom_hash[i].model; - dev->tuner_type = em28xx_eeprom_hash[i].tuner; - - em28xx_errdev("Your board has no unique USB ID.\n"); - em28xx_errdev("A hint were successfully done, " - "based on eeprom hash.\n"); - em28xx_errdev("This method is not 100%% failproof.\n"); - em28xx_errdev("If the board were missdetected, " - "please email this log to:\n"); - em28xx_errdev("\tV4L Mailing List " - " <video4linux-list@redhat.com>\n"); - em28xx_errdev("Board detected as %s\n", - em28xx_boards[dev->model].name); - - return 0; - } - } - - /* HINT method: I2C attached devices - * - * This method works for all boards. - * Uses a hash of i2c scanned devices. - * Devices with the same i2c attached chips will - * be considered equal. - * This method is less precise than the eeprom one. - */ - - /* user did not request i2c scanning => do it now */ - if (!dev->i2c_hash) - em28xx_do_i2c_scan(dev); - - for (i = 0; i < ARRAY_SIZE(em28xx_i2c_hash); i++) { - if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { - dev->model = em28xx_i2c_hash[i].model; - dev->tuner_type = em28xx_i2c_hash[i].tuner; - em28xx_errdev("Your board has no unique USB ID.\n"); - em28xx_errdev("A hint were successfully done, " - "based on i2c devicelist hash.\n"); - em28xx_errdev("This method is not 100%% failproof.\n"); - em28xx_errdev("If the board were missdetected, " - "please email this log to:\n"); - em28xx_errdev("\tV4L Mailing List " - " <video4linux-list@redhat.com>\n"); - em28xx_errdev("Board detected as %s\n", - em28xx_boards[dev->model].name); - - return 0; - } - } - - em28xx_errdev("Your board has no unique USB ID and thus need a " - "hint to be detected.\n"); - em28xx_errdev("You may try to use card=<n> insmod option to " - "workaround that.\n"); - em28xx_errdev("Please send an email with this log to:\n"); - em28xx_errdev("\tV4L Mailing List <video4linux-list@redhat.com>\n"); - em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); - em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); - - em28xx_errdev("Here is a list of valid choices for the card=<n>" - " insmod option:\n"); - for (i = 0; i < em28xx_bcount; i++) { - em28xx_errdev(" card=%d -> %s\n", - i, em28xx_boards[i].name); - } - return -1; -} - -/* ----------------------------------------------------------------------- */ -void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) -{ - if (disable_ir) { - ir->get_key = NULL; - return ; - } - - /* detect & configure */ - switch (dev->model) { - case (EM2800_BOARD_UNKNOWN): - break; - case (EM2820_BOARD_UNKNOWN): - break; - case (EM2800_BOARD_TERRATEC_CINERGY_200): - case (EM2820_BOARD_TERRATEC_CINERGY_250): - ir->ir_codes = ir_codes_em_terratec; - ir->get_key = em28xx_get_key_terratec; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM28XX Terratec)"); - break; - case (EM2820_BOARD_PINNACLE_USB_2): - ir->ir_codes = ir_codes_pinnacle_grey; - ir->get_key = em28xx_get_key_pinnacle_usb_grey; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM28XX Pinnacle PCTV)"); - break; - case (EM2820_BOARD_HAUPPAUGE_WINTV_USB_2): - ir->ir_codes = ir_codes_hauppauge_new; - ir->get_key = em28xx_get_key_em_haup; - snprintf(ir->c.name, sizeof(ir->c.name), - "i2c IR (EM2840 Hauppauge)"); - break; - case (EM2820_BOARD_MSI_VOX_USB_2): - break; - case (EM2800_BOARD_LEADTEK_WINFAST_USBII): - break; - case (EM2800_BOARD_KWORLD_USB2800): - break; - case (EM2800_BOARD_GRABBEEX_USB2800): - break; - } -} - -void em28xx_card_setup(struct em28xx *dev) -{ - em28xx_set_model(dev); - - dev->tuner_type = em28xx_boards[dev->model].tuner_type; - - /* request some modules */ - switch (dev->model) { - case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: - { - struct tveeprom tv; -#ifdef CONFIG_MODULES - request_module("tveeprom"); -#endif - /* Call first TVeeprom */ - - dev->i2c_client.addr = 0xa0 >> 1; - tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); - - dev->tuner_type = tv.tuner_type; - - if (tv.audio_processor == V4L2_IDENT_MSPX4XX) { - dev->i2s_speed = 2048000; - dev->has_msp34xx = 1; - } -#ifdef CONFIG_MODULES - if (tv.has_ir) - request_module("ir-kbd-i2c"); -#endif - break; - } - case EM2820_BOARD_KWORLD_PVRTV2800RF: - /* GPIO enables sound on KWORLD PVR TV 2800RF */ - em28xx_write_regs_req(dev, 0x00, 0x08, "\xf9", 1); - break; - case EM2820_BOARD_UNKNOWN: - case EM2800_BOARD_UNKNOWN: - if (!em28xx_hint_board(dev)) - em28xx_set_model(dev); - break; - } - - if (dev->has_snapshot_button) - em28xx_register_snapshot_button(dev); - - if (dev->valid == EM28XX_BOARD_NOT_VALIDATED) { - em28xx_errdev("\n\n"); - em28xx_errdev("The support for this board weren't " - "valid yet.\n"); - em28xx_errdev("Please send a report of having this working\n"); - em28xx_errdev("not to V4L mailing list (and/or to other " - "addresses)\n\n"); - } - - /* Allow override tuner type by a module parameter */ - if (tuner >= 0) - dev->tuner_type = tuner; - -#ifdef CONFIG_MODULES - /* request some modules */ - if (dev->has_msp34xx) - request_module("msp3400"); - if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) - request_module("saa7115"); - if (dev->decoder == EM28XX_TVP5150) - request_module("tvp5150"); - if (dev->tuner_type != TUNER_ABSENT) - request_module("tuner"); -#endif - - em28xx_config_tuner(dev); -} diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c deleted file mode 100644 index 5d837c16ee2..00000000000 --- a/drivers/media/video/em28xx/em28xx-core.c +++ /dev/null @@ -1,726 +0,0 @@ -/* - em28xx-core.c - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> - Markus Rechberger <mrechberger@gmail.com> - Mauro Carvalho Chehab <mchehab@infradead.org> - Sascha Sommer <saschasommer@freenet.de> - - 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 <linux/init.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/usb.h> -#include <linux/vmalloc.h> - -#include "em28xx.h" - -/* #define ENABLE_DEBUG_ISOC_FRAMES */ - -static unsigned int core_debug; -module_param(core_debug,int,0644); -MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); - -#define em28xx_coredbg(fmt, arg...) do {\ - if (core_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -static unsigned int reg_debug; -module_param(reg_debug,int,0644); -MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]"); - -#define em28xx_regdbg(fmt, arg...) do {\ - if (reg_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -static int alt = EM28XX_PINOUT; -module_param(alt, int, 0644); -MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); - -/* FIXME */ -#define em28xx_isocdbg(fmt, arg...) do {\ - if (core_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -/* - * em28xx_read_reg_req() - * reads data from the usb device specifying bRequest - */ -int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, - char *buf, int len) -{ - int ret, byte; - - if (dev->state & DEV_DISCONNECTED) - return(-ENODEV); - - em28xx_regdbg("req=%02x, reg=%02x ", req, reg); - - ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, buf, len, HZ); - - if (reg_debug) { - printk(ret < 0 ? " failed!\n" : "%02x values: ", ret); - for (byte = 0; byte < len; byte++) - printk(" %02x", (unsigned char)buf[byte]); - - printk("\n"); - } - - return ret; -} - -/* - * em28xx_read_reg_req() - * reads data from the usb device specifying bRequest - */ -int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg) -{ - u8 val; - int ret; - - if (dev->state & DEV_DISCONNECTED) - return(-ENODEV); - - em28xx_regdbg("req=%02x, reg=%02x:", req, reg); - - ret = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0), req, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, &val, 1, HZ); - - if (reg_debug) - printk(ret < 0 ? " failed!\n" : - "%02x\n", (unsigned char) val); - - if (ret < 0) - return ret; - - return val; -} - -int em28xx_read_reg(struct em28xx *dev, u16 reg) -{ - return em28xx_read_reg_req(dev, USB_REQ_GET_STATUS, reg); -} - -/* - * em28xx_write_regs_req() - * sends data to the usb device, specifying bRequest - */ -int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, - int len) -{ - int ret; - - /*usb_control_msg seems to expect a kmalloced buffer */ - unsigned char *bufs; - - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - - if (len < 1) - return -EINVAL; - - bufs = kmalloc(len, GFP_KERNEL); - - em28xx_regdbg("req=%02x reg=%02x:", req, reg); - - if (reg_debug) { - int i; - for (i = 0; i < len; ++i) - printk(" %02x", (unsigned char)buf[i]); - printk("\n"); - } - - if (!bufs) - return -ENOMEM; - memcpy(bufs, buf, len); - ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0000, reg, bufs, len, HZ); - if (dev->wait_after_write) - msleep(dev->wait_after_write); - - kfree(bufs); - return ret; -} - -int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len) -{ - int rc; - - rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len); - - /* Stores GPO/GPIO values at the cache, if changed - Only write values should be stored, since input on a GPIO - register will return the input bits. - Not sure what happens on reading GPO register. - */ - if (rc >= 0) { - if (reg == EM2880_R04_GPO) - dev->reg_gpo = buf[0]; - else if (reg == EM28XX_R08_GPIO) - dev->reg_gpio = buf[0]; - } - - return rc; -} - -/* - * em28xx_write_reg_bits() - * sets only some bits (specified by bitmask) of a register, by first reading - * the actual value - */ -static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val, - u8 bitmask) -{ - int oldval; - u8 newval; - - /* Uses cache for gpo/gpio registers */ - if (reg == EM2880_R04_GPO) - oldval = dev->reg_gpo; - else if (reg == EM28XX_R08_GPIO) - oldval = dev->reg_gpio; - else - oldval = em28xx_read_reg(dev, reg); - - if (oldval < 0) - return oldval; - - newval = (((u8) oldval) & ~bitmask) | (val & bitmask); - - return em28xx_write_regs(dev, reg, &newval, 1); -} - -/* - * em28xx_write_ac97() - * write a 16 bit value to the specified AC97 address (LSB first!) - */ -static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val) -{ - int ret, i; - u8 addr = reg & 0x7f; - - ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2); - if (ret < 0) - return ret; - - ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1); - if (ret < 0) - return ret; - - /* Wait up to 50 ms for AC97 command to complete */ - for (i = 0; i < 10; i++) { - ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY); - if (ret < 0) - return ret; - - if (!(ret & 0x01)) - return 0; - msleep(5); - } - em28xx_warn("AC97 command still being executed: not handled properly!\n"); - return 0; -} - -static int em28xx_set_audio_source(struct em28xx *dev) -{ - static char *enable = "\x08\x08"; - static char *disable = "\x08\x88"; - char *video = enable, *line = disable; - int ret; - u8 input; - - if (dev->is_em2800) { - if (dev->ctl_ainput) - input = EM2800_AUDIO_SRC_LINE; - else - input = EM2800_AUDIO_SRC_TUNER; - - ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1); - if (ret < 0) - return ret; - } - - if (dev->has_msp34xx) - input = EM28XX_AUDIO_SRC_TUNER; - else { - switch (dev->ctl_ainput) { - case EM28XX_AMUX_VIDEO: - input = EM28XX_AUDIO_SRC_TUNER; - break; - case EM28XX_AMUX_LINE_IN: - input = EM28XX_AUDIO_SRC_LINE; - break; - case EM28XX_AMUX_AC97_VIDEO: - input = EM28XX_AUDIO_SRC_LINE; - break; - case EM28XX_AMUX_AC97_LINE_IN: - input = EM28XX_AUDIO_SRC_LINE; - video = disable; - line = enable; - break; - } - } - - ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0); - if (ret < 0) - return ret; - msleep(5); - - /* Sets AC97 mixer registers - This is seems to be needed, even for non-ac97 configs - */ - ret = em28xx_write_ac97(dev, EM28XX_R14_VIDEO_AC97, video); - if (ret < 0) - return ret; - - ret = em28xx_write_ac97(dev, EM28XX_R10_LINE_IN_AC97, line); - - return ret; -} - -int em28xx_audio_analog_set(struct em28xx *dev) -{ - int ret; - char s[2] = { 0x00, 0x00 }; - u8 xclk = 0x07; - - s[0] |= 0x1f - dev->volume; - s[1] |= 0x1f - dev->volume; - - /* Mute */ - s[1] |= 0x80; - ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s); - - if (ret < 0) - return ret; - - if (dev->has_12mhz_i2s) - xclk |= 0x20; - - if (!dev->mute) - xclk |= 0x80; - - ret = em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, xclk, 0xa7); - if (ret < 0) - return ret; - msleep(10); - - /* Selects the proper audio input */ - ret = em28xx_set_audio_source(dev); - - /* Unmute device */ - if (!dev->mute) - s[1] &= ~0x80; - ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s); - - return ret; -} -EXPORT_SYMBOL_GPL(em28xx_audio_analog_set); - -int em28xx_colorlevels_set_default(struct em28xx *dev) -{ - em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */ - em28xx_write_regs(dev, EM28XX_R21_YOFFSET, "\x00", 1); /* brightness */ - em28xx_write_regs(dev, EM28XX_R22_UVGAIN, "\x10", 1); /* saturation */ - em28xx_write_regs(dev, EM28XX_R23_UOFFSET, "\x00", 1); - em28xx_write_regs(dev, EM28XX_R24_VOFFSET, "\x00", 1); - em28xx_write_regs(dev, EM28XX_R25_SHARPNESS, "\x00", 1); - - em28xx_write_regs(dev, EM28XX_R14_GAMMA, "\x20", 1); - em28xx_write_regs(dev, EM28XX_R15_RGAIN, "\x20", 1); - em28xx_write_regs(dev, EM28XX_R16_GGAIN, "\x20", 1); - em28xx_write_regs(dev, EM28XX_R17_BGAIN, "\x20", 1); - em28xx_write_regs(dev, EM28XX_R18_ROFFSET, "\x00", 1); - em28xx_write_regs(dev, EM28XX_R19_GOFFSET, "\x00", 1); - return em28xx_write_regs(dev, EM28XX_R1A_BOFFSET, "\x00", 1); -} - -int em28xx_capture_start(struct em28xx *dev, int start) -{ - int rc; - /* FIXME: which is the best order? */ - /* video registers are sampled by VREF */ - rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP, - start ? 0x10 : 0x00, 0x10); - if (rc < 0) - return rc; - - if (!start) { - /* disable video capture */ - rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x27", 1); - return rc; - } - - /* enable video capture */ - rc = em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); - - if (dev->mode == EM28XX_ANALOG_MODE) - rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x67", 1); - else - rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x37", 1); - - msleep(6); - - return rc; -} - -int em28xx_outfmt_set_yuv422(struct em28xx *dev) -{ - em28xx_write_regs(dev, EM28XX_R27_OUTFMT, "\x34", 1); - em28xx_write_regs(dev, EM28XX_R10_VINMODE, "\x10", 1); - return em28xx_write_regs(dev, EM28XX_R11_VINCTRL, "\x11", 1); -} - -static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax, - u8 ymin, u8 ymax) -{ - em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", - xmin, ymin, xmax, ymax); - - em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1); - em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1); - em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1); - return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1); -} - -static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart, - u16 width, u16 height) -{ - u8 cwidth = width; - u8 cheight = height; - u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01); - - em28xx_coredbg("em28xx Area Set: (%d,%d)\n", - (width | (overflow & 2) << 7), - (height | (overflow & 1) << 8)); - - em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1); - em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1); - em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1); - em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1); - return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1); -} - -static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v) -{ - u8 mode; - /* the em2800 scaler only supports scaling down to 50% */ - if (dev->is_em2800) - mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00); - else { - u8 buf[2]; - buf[0] = h; - buf[1] = h >> 8; - em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2); - buf[0] = v; - buf[1] = v >> 8; - em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2); - /* it seems that both H and V scalers must be active - to work correctly */ - mode = (h || v)? 0x30: 0x00; - } - return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30); -} - -/* FIXME: this only function read values from dev */ -int em28xx_resolution_set(struct em28xx *dev) -{ - int width, height; - width = norm_maxw(dev); - height = norm_maxh(dev) >> 1; - - em28xx_outfmt_set_yuv422(dev); - em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2); - em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2); - return em28xx_scaler_set(dev, dev->hscale, dev->vscale); -} - -int em28xx_set_alternate(struct em28xx *dev) -{ - int errCode, prev_alt = dev->alt; - int i; - unsigned int min_pkt_size = dev->width * 2 + 4; - - /* When image size is bigger than a certain value, - the frame size should be increased, otherwise, only - green screen will be received. - */ - if (dev->width * 2 * dev->height > 720 * 240 * 2) - min_pkt_size *= 2; - - for (i = 0; i < dev->num_alt; i++) { - /* stop when the selected alt setting offers enough bandwidth */ - if (dev->alt_max_pkt_size[i] >= min_pkt_size) { - dev->alt = i; - break; - /* otherwise make sure that we end up with the maximum bandwidth - because the min_pkt_size equation might be wrong... - */ - } else if (dev->alt_max_pkt_size[i] > - dev->alt_max_pkt_size[dev->alt]) - dev->alt = i; - } - - if (dev->alt != prev_alt) { - em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n", - min_pkt_size, dev->alt); - dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt]; - em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n", - dev->alt, dev->max_pkt_size); - errCode = usb_set_interface(dev->udev, 0, dev->alt); - if (errCode < 0) { - em28xx_errdev("cannot change alternate number to %d (error=%i)\n", - dev->alt, errCode); - return errCode; - } - } - return 0; -} - -int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio) -{ - int rc = 0; - - if (!gpio) - return rc; - - dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1); - if (dev->mode == EM28XX_ANALOG_MODE) - dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1); - else - dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x37", 1); - msleep(6); - - /* Send GPIO reset sequences specified at board entry */ - while (gpio->sleep >= 0) { - if (gpio->reg >= 0) { - rc = em28xx_write_reg_bits(dev, - gpio->reg, - gpio->val, - gpio->mask); - if (rc < 0) - return rc; - } - if (gpio->sleep > 0) - msleep(gpio->sleep); - - gpio++; - } - return rc; -} - -int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode) -{ - if (dev->mode == set_mode) - return 0; - - if (set_mode == EM28XX_MODE_UNDEFINED) { - dev->mode = set_mode; - return 0; - } - - dev->mode = set_mode; - - if (dev->mode == EM28XX_DIGITAL_MODE) - return em28xx_gpio_set(dev, dev->digital_gpio); - else - return em28xx_gpio_set(dev, dev->analog_gpio); -} -EXPORT_SYMBOL_GPL(em28xx_set_mode); - -/* ------------------------------------------------------------------ - URB control - ------------------------------------------------------------------*/ - -/* - * IRQ callback, called by URB callback - */ -static void em28xx_irq_callback(struct urb *urb) -{ - struct em28xx_dmaqueue *dma_q = urb->context; - struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); - int rc, i; - - /* Copy data from URB */ - spin_lock(&dev->slock); - rc = dev->isoc_ctl.isoc_copy(dev, urb); - spin_unlock(&dev->slock); - - /* Reset urb buffers */ - for (i = 0; i < urb->number_of_packets; i++) { - urb->iso_frame_desc[i].status = 0; - urb->iso_frame_desc[i].actual_length = 0; - } - urb->status = 0; - - urb->status = usb_submit_urb(urb, GFP_ATOMIC); - if (urb->status) { - em28xx_isocdbg("urb resubmit failed (error=%i)\n", - urb->status); - } -} - -/* - * Stop and Deallocate URBs - */ -void em28xx_uninit_isoc(struct em28xx *dev) -{ - struct urb *urb; - int i; - - em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n"); - - dev->isoc_ctl.nfields = -1; - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = dev->isoc_ctl.urb[i]; - if (urb) { - usb_kill_urb(urb); - usb_unlink_urb(urb); - if (dev->isoc_ctl.transfer_buffer[i]) { - usb_buffer_free(dev->udev, - urb->transfer_buffer_length, - dev->isoc_ctl.transfer_buffer[i], - urb->transfer_dma); - } - usb_free_urb(urb); - dev->isoc_ctl.urb[i] = NULL; - } - dev->isoc_ctl.transfer_buffer[i] = NULL; - } - - kfree(dev->isoc_ctl.urb); - kfree(dev->isoc_ctl.transfer_buffer); - - dev->isoc_ctl.urb = NULL; - dev->isoc_ctl.transfer_buffer = NULL; - dev->isoc_ctl.num_bufs = 0; - - em28xx_capture_start(dev, 0); -} -EXPORT_SYMBOL_GPL(em28xx_uninit_isoc); - -/* - * Allocate URBs and start IRQ - */ -int em28xx_init_isoc(struct em28xx *dev, int max_packets, - int num_bufs, int max_pkt_size, - int (*isoc_copy) (struct em28xx *dev, struct urb *urb)) -{ - struct em28xx_dmaqueue *dma_q = &dev->vidq; - int i; - int sb_size, pipe; - struct urb *urb; - int j, k; - int rc; - - em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n"); - - /* De-allocates all pending stuff */ - em28xx_uninit_isoc(dev); - - dev->isoc_ctl.isoc_copy = isoc_copy; - dev->isoc_ctl.num_bufs = num_bufs; - - dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); - if (!dev->isoc_ctl.urb) { - em28xx_errdev("cannot alloc memory for usb buffers\n"); - return -ENOMEM; - } - - dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs, - GFP_KERNEL); - if (!dev->isoc_ctl.transfer_buffer) { - em28xx_errdev("cannot allocate memory for usbtransfer\n"); - kfree(dev->isoc_ctl.urb); - return -ENOMEM; - } - - dev->isoc_ctl.max_pkt_size = max_pkt_size; - dev->isoc_ctl.buf = NULL; - - sb_size = max_packets * dev->isoc_ctl.max_pkt_size; - - /* allocate urbs and transfer buffers */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - urb = usb_alloc_urb(max_packets, GFP_KERNEL); - if (!urb) { - em28xx_err("cannot alloc isoc_ctl.urb %i\n", i); - em28xx_uninit_isoc(dev); - return -ENOMEM; - } - dev->isoc_ctl.urb[i] = urb; - - dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev, - sb_size, GFP_KERNEL, &urb->transfer_dma); - if (!dev->isoc_ctl.transfer_buffer[i]) { - em28xx_err("unable to allocate %i bytes for transfer" - " buffer %i%s\n", - sb_size, i, - in_interrupt()?" while in int":""); - em28xx_uninit_isoc(dev); - return -ENOMEM; - } - memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size); - - /* FIXME: this is a hack - should be - 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK' - should also be using 'desc.bInterval' - */ - pipe = usb_rcvisocpipe(dev->udev, - dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84); - - usb_fill_int_urb(urb, dev->udev, pipe, - dev->isoc_ctl.transfer_buffer[i], sb_size, - em28xx_irq_callback, dma_q, 1); - - urb->number_of_packets = max_packets; - urb->transfer_flags = URB_ISO_ASAP; - - k = 0; - for (j = 0; j < max_packets; j++) { - urb->iso_frame_desc[j].offset = k; - urb->iso_frame_desc[j].length = - dev->isoc_ctl.max_pkt_size; - k += dev->isoc_ctl.max_pkt_size; - } - } - - init_waitqueue_head(&dma_q->wq); - - em28xx_capture_start(dev, 1); - - /* submit urbs and enables IRQ */ - for (i = 0; i < dev->isoc_ctl.num_bufs; i++) { - rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC); - if (rc) { - em28xx_err("submit of urb %i failed (error=%i)\n", i, - rc); - em28xx_uninit_isoc(dev); - return rc; - } - } - - return 0; -} -EXPORT_SYMBOL_GPL(em28xx_init_isoc); diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c deleted file mode 100644 index 4b992bc0083..00000000000 --- a/drivers/media/video/em28xx/em28xx-dvb.c +++ /dev/null @@ -1,519 +0,0 @@ -/* - DVB device driver for em28xx - - (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org> - - (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com> - - Fixes for the driver to properly work with HVR-950 - - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick - - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600 - - (c) 2008 Aidan Thornton <makosoft@googlemail.com> - - Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by: - (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au> - (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] - - 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. - */ - -#include <linux/kernel.h> -#include <linux/usb.h> - -#include "em28xx.h" -#include <media/v4l2-common.h> -#include <media/videobuf-vmalloc.h> - -#include "lgdt330x.h" -#include "zl10353.h" -#ifdef EM28XX_DRX397XD_SUPPORT -#include "drx397xD.h" -#endif - -MODULE_DESCRIPTION("driver for em28xx based DVB cards"); -MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); -MODULE_LICENSE("GPL"); - -static unsigned int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "enable debug messages [dvb]"); - -DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -#define dprintk(level, fmt, arg...) do { \ -if (debug >= level) \ - printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ -} while (0) - -#define EM28XX_DVB_NUM_BUFS 5 -#define EM28XX_DVB_MAX_PACKETSIZE 564 -#define EM28XX_DVB_MAX_PACKETS 64 - -struct em28xx_dvb { - struct dvb_frontend *frontend; - - /* feed count management */ - struct mutex lock; - int nfeeds; - - /* general boilerplate stuff */ - struct dvb_adapter adapter; - struct dvb_demux demux; - struct dmxdev dmxdev; - struct dmx_frontend fe_hw; - struct dmx_frontend fe_mem; - struct dvb_net net; -}; - - -static inline void print_err_status(struct em28xx *dev, - int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - dprintk(1, "URB status %d [%s].\n", status, errmsg); - } else { - dprintk(1, "URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - -static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb) -{ - int i; - - if (!dev) - return 0; - - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) - return 0; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - if (urb->status == -ENOENT) - return 0; - } - - for (i = 0; i < urb->number_of_packets; i++) { - int status = urb->iso_frame_desc[i].status; - - if (status < 0) { - print_err_status(dev, i, status); - if (urb->iso_frame_desc[i].status != -EPROTO) - continue; - } - - dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer + - urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - } - - return 0; -} - -static int start_streaming(struct em28xx_dvb *dvb) -{ - int rc; - struct em28xx *dev = dvb->adapter.priv; - - usb_set_interface(dev->udev, 0, 1); - rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); - if (rc < 0) - return rc; - - return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS, - EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE, - dvb_isoc_copy); -} - -static int stop_streaming(struct em28xx_dvb *dvb) -{ - struct em28xx *dev = dvb->adapter.priv; - - em28xx_uninit_isoc(dev); - - em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); - - return 0; -} - -static int start_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct em28xx_dvb *dvb = demux->priv; - int rc, ret; - - if (!demux->dmx.frontend) - return -EINVAL; - - mutex_lock(&dvb->lock); - dvb->nfeeds++; - rc = dvb->nfeeds; - - if (dvb->nfeeds == 1) { - ret = start_streaming(dvb); - if (ret < 0) - rc = ret; - } - - mutex_unlock(&dvb->lock); - return rc; -} - -static int stop_feed(struct dvb_demux_feed *feed) -{ - struct dvb_demux *demux = feed->demux; - struct em28xx_dvb *dvb = demux->priv; - int err = 0; - - mutex_lock(&dvb->lock); - dvb->nfeeds--; - - if (0 == dvb->nfeeds) - err = stop_streaming(dvb); - - mutex_unlock(&dvb->lock); - return err; -} - - - -/* ------------------------------------------------------------------ */ -static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) -{ - struct em28xx *dev = fe->dvb->priv; - - if (acquire) - return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); - else - return em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); -} - -/* ------------------------------------------------------------------ */ - -static struct lgdt330x_config em2880_lgdt3303_dev = { - .demod_address = 0x0e, - .demod_chip = LGDT3303, -}; - -static struct zl10353_config em28xx_zl10353_with_xc3028 = { - .demod_address = (0x1e >> 1), - .no_tuner = 1, - .parallel_ts = 1, - .if2 = 45600, -}; - -#ifdef EM28XX_DRX397XD_SUPPORT -/* [TODO] djh - not sure yet what the device config needs to contain */ -static struct drx397xD_config em28xx_drx397xD_with_xc3028 = { - .demod_address = (0xe0 >> 1), -}; -#endif - -/* ------------------------------------------------------------------ */ - -static int attach_xc3028(u8 addr, struct em28xx *dev) -{ - struct dvb_frontend *fe; - struct xc2028_config cfg; - - memset(&cfg, 0, sizeof(cfg)); - cfg.i2c_adap = &dev->i2c_adap; - cfg.i2c_addr = addr; - cfg.callback = em28xx_tuner_callback; - - if (!dev->dvb->frontend) { - printk(KERN_ERR "%s/2: dvb frontend not attached. " - "Can't attach xc3028\n", - dev->name); - return -EINVAL; - } - - fe = dvb_attach(xc2028_attach, dev->dvb->frontend, &cfg); - if (!fe) { - printk(KERN_ERR "%s/2: xc3028 attach failed\n", - dev->name); - dvb_frontend_detach(dev->dvb->frontend); - dev->dvb->frontend = NULL; - return -EINVAL; - } - - printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name); - - return 0; -} - -/* ------------------------------------------------------------------ */ - -int register_dvb(struct em28xx_dvb *dvb, - struct module *module, - struct em28xx *dev, - struct device *device) -{ - int result; - - mutex_init(&dvb->lock); - - /* register adapter */ - result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, - adapter_nr); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", - dev->name, result); - goto fail_adapter; - } - - /* Ensure all frontends negotiate bus access */ - dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl; - - dvb->adapter.priv = dev; - - /* register frontend */ - result = dvb_register_frontend(&dvb->adapter, dvb->frontend); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", - dev->name, result); - goto fail_frontend; - } - - /* register demux stuff */ - dvb->demux.dmx.capabilities = - DMX_TS_FILTERING | DMX_SECTION_FILTERING | - DMX_MEMORY_BASED_FILTERING; - dvb->demux.priv = dvb; - dvb->demux.filternum = 256; - dvb->demux.feednum = 256; - dvb->demux.start_feed = start_feed; - dvb->demux.stop_feed = stop_feed; - - result = dvb_dmx_init(&dvb->demux); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", - dev->name, result); - goto fail_dmx; - } - - dvb->dmxdev.filternum = 256; - dvb->dmxdev.demux = &dvb->demux.dmx; - dvb->dmxdev.capabilities = 0; - result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); - if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", - dev->name, result); - goto fail_dmxdev; - } - - dvb->fe_hw.source = DMX_FRONTEND_0; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", - dev->name, result); - goto fail_fe_hw; - } - - dvb->fe_mem.source = DMX_MEMORY_FE; - result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); - if (result < 0) { - printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", - dev->name, result); - goto fail_fe_mem; - } - - result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); - if (result < 0) { - printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n", - dev->name, result); - goto fail_fe_conn; - } - - /* register network adapter */ - dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx); - return 0; - -fail_fe_conn: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); -fail_fe_mem: - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); -fail_fe_hw: - dvb_dmxdev_release(&dvb->dmxdev); -fail_dmxdev: - dvb_dmx_release(&dvb->demux); -fail_dmx: - dvb_unregister_frontend(dvb->frontend); -fail_frontend: - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -fail_adapter: - return result; -} - -static void unregister_dvb(struct em28xx_dvb *dvb) -{ - dvb_net_release(&dvb->net); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem); - dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw); - dvb_dmxdev_release(&dvb->dmxdev); - dvb_dmx_release(&dvb->demux); - dvb_unregister_frontend(dvb->frontend); - dvb_frontend_detach(dvb->frontend); - dvb_unregister_adapter(&dvb->adapter); -} - - -static int dvb_init(struct em28xx *dev) -{ - int result = 0; - struct em28xx_dvb *dvb; - - if (!dev->has_dvb) { - /* This device does not support the extension */ - return 0; - } - - dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); - - if (dvb == NULL) { - printk(KERN_INFO "em28xx_dvb: memory allocation failed\n"); - return -ENOMEM; - } - dev->dvb = dvb; - - em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); - /* init frontend */ - switch (dev->model) { - case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: - case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: - case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: - dvb->frontend = dvb_attach(lgdt330x_attach, - &em2880_lgdt3303_dev, - &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { - result = -EINVAL; - goto out_free; - } - break; - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: - dvb->frontend = dvb_attach(zl10353_attach, - &em28xx_zl10353_with_xc3028, - &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { - result = -EINVAL; - goto out_free; - } - break; - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: -#ifdef EM28XX_DRX397XD_SUPPORT - /* We don't have the config structure properly populated, so - this is commented out for now */ - dvb->frontend = dvb_attach(drx397xD_attach, - &em28xx_drx397xD_with_xc3028, - &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { - result = -EINVAL; - goto out_free; - } - break; -#endif - case EM2880_BOARD_TERRATEC_HYBRID_XS: - dvb->frontend = dvb_attach(zl10353_attach, - &em28xx_zl10353_with_xc3028, - &dev->i2c_adap); - if (attach_xc3028(0x61, dev) < 0) { - result = -EINVAL; - goto out_free; - } - break; - default: - printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" - " isn't supported yet\n", - dev->name); - break; - } - if (NULL == dvb->frontend) { - printk(KERN_ERR - "%s/2: frontend initialization failed\n", - dev->name); - result = -EINVAL; - goto out_free; - } - - /* register everything */ - result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); - - if (result < 0) - goto out_free; - - em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); - printk(KERN_INFO "Successfully loaded em28xx-dvb\n"); - return 0; - -out_free: - em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); - kfree(dvb); - dev->dvb = NULL; - return result; -} - -static int dvb_fini(struct em28xx *dev) -{ - if (!dev->has_dvb) { - /* This device does not support the extension */ - return 0; - } - - if (dev->dvb) { - unregister_dvb(dev->dvb); - dev->dvb = NULL; - } - - return 0; -} - -static struct em28xx_ops dvb_ops = { - .id = EM28XX_DVB, - .name = "Em28xx dvb Extension", - .init = dvb_init, - .fini = dvb_fini, -}; - -static int __init em28xx_dvb_register(void) -{ - return em28xx_register_extension(&dvb_ops); -} - -static void __exit em28xx_dvb_unregister(void) -{ - em28xx_unregister_extension(&dvb_ops); -} - -module_init(em28xx_dvb_register); -module_exit(em28xx_dvb_unregister); diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c deleted file mode 100644 index 97853384c94..00000000000 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - em28xx-i2c.c - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> - Markus Rechberger <mrechberger@gmail.com> - Mauro Carvalho Chehab <mchehab@infradead.org> - Sascha Sommer <saschasommer@freenet.de> - - 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 <linux/module.h> -#include <linux/kernel.h> -#include <linux/usb.h> -#include <linux/i2c.h> - -#include "em28xx.h" -#include "tuner-xc2028.h" -#include <media/v4l2-common.h> -#include <media/tuner.h> - -/* ----------------------------------------------------------- */ - -static unsigned int i2c_scan; -module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); - -static unsigned int i2c_debug; -module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); - - -#define dprintk1(lvl, fmt, args...) \ -do { \ - if (i2c_debug >= lvl) { \ - printk(fmt, ##args); \ - } \ -} while (0) - -#define dprintk2(lvl, fmt, args...) \ -do { \ - if (i2c_debug >= lvl) { \ - printk(KERN_DEBUG "%s at %s: " fmt, \ - dev->name, __func__ , ##args); \ - } \ -} while (0) - -/* - * em2800_i2c_send_max4() - * send up to 4 bytes to the i2c device - */ -static int em2800_i2c_send_max4(struct em28xx *dev, unsigned char addr, - char *buf, int len) -{ - int ret; - int write_timeout; - unsigned char b2[6]; - BUG_ON(len < 1 || len > 4); - b2[5] = 0x80 + len - 1; - b2[4] = addr; - b2[3] = buf[0]; - if (len > 1) - b2[2] = buf[1]; - if (len > 2) - b2[1] = buf[2]; - if (len > 3) - b2[0] = buf[3]; - - ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); - if (ret != 2 + len) { - em28xx_warn("writing to i2c device failed (error=%i)\n", ret); - return -EIO; - } - for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0; - write_timeout -= 5) { - ret = dev->em28xx_read_reg(dev, 0x05); - if (ret == 0x80 + len - 1) - return len; - msleep(5); - } - em28xx_warn("i2c write timed out\n"); - return -EIO; -} - -/* - * em2800_i2c_send_bytes() - */ -static int em2800_i2c_send_bytes(void *data, unsigned char addr, char *buf, - short len) -{ - char *bufPtr = buf; - int ret; - int wrcount = 0; - int count; - int maxLen = 4; - struct em28xx *dev = (struct em28xx *)data; - while (len > 0) { - count = (len > maxLen) ? maxLen : len; - ret = em2800_i2c_send_max4(dev, addr, bufPtr, count); - if (ret > 0) { - len -= count; - bufPtr += count; - wrcount += count; - } else - return (ret < 0) ? ret : -EFAULT; - } - return wrcount; -} - -/* - * em2800_i2c_check_for_device() - * check if there is a i2c_device at the supplied address - */ -static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr) -{ - char msg; - int ret; - int write_timeout; - msg = addr; - ret = dev->em28xx_write_regs(dev, 0x04, &msg, 1); - if (ret < 0) { - em28xx_warn("setting i2c device address failed (error=%i)\n", - ret); - return ret; - } - msg = 0x84; - ret = dev->em28xx_write_regs(dev, 0x05, &msg, 1); - if (ret < 0) { - em28xx_warn("preparing i2c read failed (error=%i)\n", ret); - return ret; - } - for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0; - write_timeout -= 5) { - unsigned msg = dev->em28xx_read_reg(dev, 0x5); - if (msg == 0x94) - return -ENODEV; - else if (msg == 0x84) - return 0; - msleep(5); - } - return -ENODEV; -} - -/* - * em2800_i2c_recv_bytes() - * read from the i2c device - */ -static int em2800_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, - char *buf, int len) -{ - int ret; - /* check for the device and set i2c read address */ - ret = em2800_i2c_check_for_device(dev, addr); - if (ret) { - em28xx_warn - ("preparing read at i2c address 0x%x failed (error=%i)\n", - addr, ret); - return ret; - } - ret = dev->em28xx_read_reg_req_len(dev, 0x0, 0x3, buf, len); - if (ret < 0) { - em28xx_warn("reading from i2c device at 0x%x failed (error=%i)", - addr, ret); - return ret; - } - return ret; -} - -/* - * em28xx_i2c_send_bytes() - * untested for more than 4 bytes - */ -static int em28xx_i2c_send_bytes(void *data, unsigned char addr, char *buf, - short len, int stop) -{ - int wrcount = 0; - struct em28xx *dev = (struct em28xx *)data; - - wrcount = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); - - return wrcount; -} - -/* - * em28xx_i2c_recv_bytes() - * read a byte from the i2c device - */ -static int em28xx_i2c_recv_bytes(struct em28xx *dev, unsigned char addr, - char *buf, int len) -{ - int ret; - ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); - if (ret < 0) { - em28xx_warn("reading i2c device failed (error=%i)\n", ret); - return ret; - } - if (dev->em28xx_read_reg(dev, 0x5) != 0) - return -ENODEV; - return ret; -} - -/* - * em28xx_i2c_check_for_device() - * check if there is a i2c_device at the supplied address - */ -static int em28xx_i2c_check_for_device(struct em28xx *dev, unsigned char addr) -{ - char msg; - int ret; - msg = addr; - - ret = dev->em28xx_read_reg_req(dev, 2, addr); - if (ret < 0) { - em28xx_warn("reading from i2c device failed (error=%i)\n", ret); - return ret; - } - if (dev->em28xx_read_reg(dev, 0x5) != 0) - return -ENODEV; - return 0; -} - -/* - * em28xx_i2c_xfer() - * the main i2c transfer function - */ -static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg msgs[], int num) -{ - struct em28xx *dev = i2c_adap->algo_data; - int addr, rc, i, byte; - - if (num <= 0) - return 0; - for (i = 0; i < num; i++) { - addr = msgs[i].addr << 1; - dprintk2(2, "%s %s addr=%x len=%d:", - (msgs[i].flags & I2C_M_RD) ? "read" : "write", - i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len); - if (!msgs[i].len) { /* no len: check only for device presence */ - if (dev->is_em2800) - rc = em2800_i2c_check_for_device(dev, addr); - else - rc = em28xx_i2c_check_for_device(dev, addr); - if (rc < 0) { - dprintk2(2, " no device\n"); - return rc; - } - - } else if (msgs[i].flags & I2C_M_RD) { - /* read bytes */ - if (dev->is_em2800) - rc = em2800_i2c_recv_bytes(dev, addr, - msgs[i].buf, - msgs[i].len); - else - rc = em28xx_i2c_recv_bytes(dev, addr, - msgs[i].buf, - msgs[i].len); - if (i2c_debug >= 2) { - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - } - } else { - /* write bytes */ - if (i2c_debug >= 2) { - for (byte = 0; byte < msgs[i].len; byte++) - printk(" %02x", msgs[i].buf[byte]); - } - if (dev->is_em2800) - rc = em2800_i2c_send_bytes(dev, addr, - msgs[i].buf, - msgs[i].len); - else - rc = em28xx_i2c_send_bytes(dev, addr, - msgs[i].buf, - msgs[i].len, - i == num - 1); - } - if (rc < 0) - goto err; - if (i2c_debug >= 2) - printk("\n"); - } - - return num; -err: - dprintk2(2, " ERROR: %i\n", rc); - return rc; -} - -/* based on linux/sunrpc/svcauth.h and linux/hash.h - * The original hash function returns a different value, if arch is x86_64 - * or i386. - */ -static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits) -{ - unsigned long hash = 0; - unsigned long l = 0; - int len = 0; - unsigned char c; - do { - if (len == length) { - c = (char)len; - len = -1; - } else - c = *buf++; - l = (l << 8) | c; - len++; - if ((len & (32 / 8 - 1)) == 0) - hash = ((hash^l) * 0x9e370001UL); - } while (len); - - return (hash >> (32 - bits)) & 0xffffffffUL; -} - -static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len) -{ - unsigned char buf, *p = eedata; - struct em28xx_eeprom *em_eeprom = (void *)eedata; - int i, err, size = len, block; - - dev->i2c_client.addr = 0xa0 >> 1; - - /* Check if board has eeprom */ - err = i2c_master_recv(&dev->i2c_client, &buf, 0); - if (err < 0) - return -1; - - buf = 0; - - err = i2c_master_send(&dev->i2c_client, &buf, 1); - if (err != 1) { - printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n", - dev->name, err); - return -1; - } - while (size > 0) { - if (size > 16) - block = 16; - else - block = size; - - if (block != - (err = i2c_master_recv(&dev->i2c_client, p, block))) { - printk(KERN_WARNING - "%s: i2c eeprom read error (err=%d)\n", - dev->name, err); - return -1; - } - size -= block; - p += block; - } - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - printk(KERN_INFO "%s: i2c eeprom %02x:", dev->name, i); - printk(" %02x", eedata[i]); - if (15 == (i % 16)) - printk("\n"); - } - - if (em_eeprom->id == 0x9567eb1a) - dev->hash = em28xx_hash_mem(eedata, len, 32); - - printk(KERN_INFO "EEPROM ID= 0x%08x, hash = 0x%08lx\n", - em_eeprom->id, dev->hash); - printk(KERN_INFO "Vendor/Product ID= %04x:%04x\n", em_eeprom->vendor_ID, - em_eeprom->product_ID); - - switch (em_eeprom->chip_conf >> 4 & 0x3) { - case 0: - printk(KERN_INFO "No audio on board.\n"); - break; - case 1: - printk(KERN_INFO "AC97 audio (5 sample rates)\n"); - break; - case 2: - printk(KERN_INFO "I2S audio, sample rate=32k\n"); - break; - case 3: - printk(KERN_INFO "I2S audio, 3 sample rates\n"); - break; - } - - if (em_eeprom->chip_conf & 1 << 3) - printk(KERN_INFO "USB Remote wakeup capable\n"); - - if (em_eeprom->chip_conf & 1 << 2) - printk(KERN_INFO "USB Self power capable\n"); - - switch (em_eeprom->chip_conf & 0x3) { - case 0: - printk(KERN_INFO "500mA max power\n"); - break; - case 1: - printk(KERN_INFO "400mA max power\n"); - break; - case 2: - printk(KERN_INFO "300mA max power\n"); - break; - case 3: - printk(KERN_INFO "200mA max power\n"); - break; - } - printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", - em_eeprom->string_idx_table, - em_eeprom->string1, - em_eeprom->string2, - em_eeprom->string3); - - return 0; -} - -/* ----------------------------------------------------------- */ - -/* - * functionality() - */ -static u32 functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_SMBUS_EMUL; -} - -/* - * attach_inform() - * gets called when a device attaches to the i2c bus - * does some basic configuration - */ -static int attach_inform(struct i2c_client *client) -{ - struct em28xx *dev = client->adapter->algo_data; - - switch (client->addr << 1) { - case 0x86: - case 0x84: - case 0x96: - case 0x94: - { - struct v4l2_priv_tun_config tda9887_cfg; - - struct tuner_setup tun_setup; - - tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; - tun_setup.type = TUNER_TDA9887; - tun_setup.addr = client->addr; - - em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, - &tun_setup); - - tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &dev->tda9887_conf; - em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG, - &tda9887_cfg); - break; - } - case 0x42: - dprintk1(1, "attach_inform: saa7114 detected.\n"); - break; - case 0x4a: - dprintk1(1, "attach_inform: saa7113 detected.\n"); - break; - case 0xa0: - dprintk1(1, "attach_inform: eeprom detected.\n"); - break; - case 0x60: - case 0x8e: - { - struct IR_i2c *ir = i2c_get_clientdata(client); - dprintk1(1, "attach_inform: IR detected (%s).\n", - ir->phys); - em28xx_set_ir(dev, ir); - break; - } - case 0x80: - case 0x88: - dprintk1(1, "attach_inform: msp34xx detected.\n"); - break; - case 0xb8: - case 0xba: - dprintk1(1, "attach_inform: tvp5150 detected.\n"); - break; - - default: - if (!dev->tuner_addr) - dev->tuner_addr = client->addr; - - dprintk1(1, "attach inform: detected I2C address %x\n", - client->addr << 1); - - } - - return 0; -} - -static struct i2c_algorithm em28xx_algo = { - .master_xfer = em28xx_i2c_xfer, - .functionality = functionality, -}; - -static struct i2c_adapter em28xx_adap_template = { - .owner = THIS_MODULE, - .class = I2C_CLASS_TV_ANALOG, - .name = "em28xx", - .id = I2C_HW_B_EM28XX, - .algo = &em28xx_algo, - .client_register = attach_inform, -}; - -static struct i2c_client em28xx_client_template = { - .name = "em28xx internal", -}; - -/* ----------------------------------------------------------- */ - -/* - * i2c_devs - * incomplete list of known devices - */ -static char *i2c_devs[128] = { - [0x4a >> 1] = "saa7113h", - [0x60 >> 1] = "remote IR sensor", - [0x8e >> 1] = "remote IR sensor", - [0x86 >> 1] = "tda9887", - [0x80 >> 1] = "msp34xx", - [0x88 >> 1] = "msp34xx", - [0xa0 >> 1] = "eeprom", - [0xb8 >> 1] = "tvp5150a", - [0xba >> 1] = "tvp5150a", - [0xc0 >> 1] = "tuner (analog)", - [0xc2 >> 1] = "tuner (analog)", - [0xc4 >> 1] = "tuner (analog)", - [0xc6 >> 1] = "tuner (analog)", -}; - -/* - * do_i2c_scan() - * check i2c address range for devices - */ -void em28xx_do_i2c_scan(struct em28xx *dev) -{ - u8 i2c_devicelist[128]; - unsigned char buf; - int i, rc; - - memset(i2c_devicelist, 0, ARRAY_SIZE(i2c_devicelist)); - - for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { - dev->i2c_client.addr = i; - rc = i2c_master_recv(&dev->i2c_client, &buf, 0); - if (rc < 0) - continue; - i2c_devicelist[i] = i; - printk(KERN_INFO "%s: found i2c device @ 0x%x [%s]\n", - dev->name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); - } - - dev->i2c_hash = em28xx_hash_mem(i2c_devicelist, - ARRAY_SIZE(i2c_devicelist), 32); -} - -/* - * em28xx_i2c_call_clients() - * send commands to all attached i2c devices - */ -void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg) -{ - BUG_ON(NULL == dev->i2c_adap.algo_data); - i2c_clients_command(&dev->i2c_adap, cmd, arg); -} - -/* - * em28xx_i2c_register() - * register i2c bus - */ -int em28xx_i2c_register(struct em28xx *dev) -{ - BUG_ON(!dev->em28xx_write_regs || !dev->em28xx_read_reg); - BUG_ON(!dev->em28xx_write_regs_req || !dev->em28xx_read_reg_req); - dev->i2c_adap = em28xx_adap_template; - dev->i2c_adap.dev.parent = &dev->udev->dev; - strcpy(dev->i2c_adap.name, dev->name); - dev->i2c_adap.algo_data = dev; - i2c_add_adapter(&dev->i2c_adap); - - dev->i2c_client = em28xx_client_template; - dev->i2c_client.adapter = &dev->i2c_adap; - - em28xx_i2c_eeprom(dev, dev->eedata, sizeof(dev->eedata)); - - if (i2c_scan) - em28xx_do_i2c_scan(dev); - return 0; -} - -/* - * em28xx_i2c_unregister() - * unregister i2c_bus - */ -int em28xx_i2c_unregister(struct em28xx *dev) -{ - i2c_del_adapter(&dev->i2c_adap); - return 0; -} diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c deleted file mode 100644 index eab3d9511af..00000000000 --- a/drivers/media/video/em28xx/em28xx-input.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - handle em28xx IR remotes via linux kernel input layer. - - Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> - Markus Rechberger <mrechberger@gmail.com> - Mauro Carvalho Chehab <mchehab@infradead.org> - Sascha Sommer <saschasommer@freenet.de> - - 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/module.h> -#include <linux/init.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/input.h> -#include <linux/usb.h> - -#include "em28xx.h" - -#define EM28XX_SNAPSHOT_KEY KEY_CAMERA -#define EM28XX_SBUTTON_QUERY_INTERVAL 500 -#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20 - -static unsigned int ir_debug; -module_param(ir_debug, int, 0644); -MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); - -#define dprintk(fmt, arg...) \ - if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \ - } - -/* ----------------------------------------------------------------------- */ - -int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char b; - - /* poll IR chip */ - if (1 != i2c_master_recv(&ir->c, &b, 1)) { - dprintk("read error\n"); - return -EIO; - } - - /* it seems that 0xFE indicates that a button is still hold - down, while 0xff indicates that no button is hold - down. 0xfe sequences are sometimes interrupted by 0xFF */ - - dprintk("key %02x\n", b); - - if (b == 0xff) - return 0; - - if (b == 0xfe) - /* keep old data */ - return 1; - - *ir_key = b; - *ir_raw = b; - return 1; -} - - -int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) -{ - unsigned char buf[2]; - unsigned char code; - - /* poll IR chip */ - if (2 != i2c_master_recv(&ir->c, buf, 2)) - return -EIO; - - /* Does eliminate repeated parity code */ - if (buf[1] == 0xff) - return 0; - - ir->old = buf[1]; - - /* Rearranges bits to the right order */ - code = ((buf[0]&0x01)<<5) | /* 0010 0000 */ - ((buf[0]&0x02)<<3) | /* 0001 0000 */ - ((buf[0]&0x04)<<1) | /* 0000 1000 */ - ((buf[0]&0x08)>>1) | /* 0000 0100 */ - ((buf[0]&0x10)>>3) | /* 0000 0010 */ - ((buf[0]&0x20)>>5); /* 0000 0001 */ - - dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n", - code, buf[0]); - - /* return key */ - *ir_key = code; - *ir_raw = code; - return 1; -} - -int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, - u32 *ir_raw) -{ - unsigned char buf[3]; - - /* poll IR chip */ - - if (3 != i2c_master_recv(&ir->c, buf, 3)) { - dprintk("read error\n"); - return -EIO; - } - - dprintk("key %02x\n", buf[2]&0x3f); - if (buf[0] != 0x00) - return 0; - - *ir_key = buf[2]&0x3f; - *ir_raw = buf[2]&0x3f; - - return 1; -} - -static void em28xx_query_sbutton(struct work_struct *work) -{ - /* Poll the register and see if the button is depressed */ - struct em28xx *dev = - container_of(work, struct em28xx, sbutton_query_work.work); - int ret; - - ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP); - - if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) { - u8 cleared; - /* Button is depressed, clear the register */ - cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT; - em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1); - - /* Not emulate the keypress */ - input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, - 1); - /* Now unpress the key */ - input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY, - 0); - } - - /* Schedule next poll */ - schedule_delayed_work(&dev->sbutton_query_work, - msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); -} - -void em28xx_register_snapshot_button(struct em28xx *dev) -{ - struct input_dev *input_dev; - int err; - - em28xx_info("Registering snapshot button...\n"); - input_dev = input_allocate_device(); - if (!input_dev) { - em28xx_errdev("input_allocate_device failed\n"); - return; - } - - usb_make_path(dev->udev, dev->snapshot_button_path, - sizeof(dev->snapshot_button_path)); - strlcat(dev->snapshot_button_path, "/sbutton", - sizeof(dev->snapshot_button_path)); - INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton); - - input_dev->name = "em28xx snapshot button"; - input_dev->phys = dev->snapshot_button_path; - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); - set_bit(EM28XX_SNAPSHOT_KEY, input_dev->keybit); - input_dev->keycodesize = 0; - input_dev->keycodemax = 0; - input_dev->id.bustype = BUS_USB; - input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct); - input_dev->id.version = 1; - input_dev->dev.parent = &dev->udev->dev; - - err = input_register_device(input_dev); - if (err) { - em28xx_errdev("input_register_device failed\n"); - input_free_device(input_dev); - return; - } - - dev->sbutton_input_dev = input_dev; - schedule_delayed_work(&dev->sbutton_query_work, - msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL)); - return; - -} - -void em28xx_deregister_snapshot_button(struct em28xx *dev) -{ - if (dev->sbutton_input_dev != NULL) { - em28xx_info("Deregistering snapshot button\n"); - cancel_rearming_delayed_work(&dev->sbutton_query_work); - input_unregister_device(dev->sbutton_input_dev); - dev->sbutton_input_dev = NULL; - } - return; -} - -/* ---------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h deleted file mode 100644 index fac1ab23f62..00000000000 --- a/drivers/media/video/em28xx/em28xx-reg.h +++ /dev/null @@ -1,89 +0,0 @@ -#define EM_GPIO_0 (1 << 0) -#define EM_GPIO_1 (1 << 1) -#define EM_GPIO_2 (1 << 2) -#define EM_GPIO_3 (1 << 3) -#define EM_GPIO_4 (1 << 4) -#define EM_GPIO_5 (1 << 5) -#define EM_GPIO_6 (1 << 6) -#define EM_GPIO_7 (1 << 7) - -#define EM_GPO_0 (1 << 0) -#define EM_GPO_1 (1 << 1) -#define EM_GPO_2 (1 << 2) -#define EM_GPO_3 (1 << 3) - -/* em2800 registers */ -#define EM2800_R08_AUDIOSRC 0x08 - -/* em28xx registers */ - - /* GPIO/GPO registers */ -#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */ -#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */ - -#define EM28XX_R06_I2C_CLK 0x06 -#define EM28XX_R0A_CHIPID 0x0a -#define EM28XX_R0C_USBSUSP 0x0c /* */ - -#define EM28XX_R0E_AUDIOSRC 0x0e -#define EM28XX_R0F_XCLK 0x0f - -#define EM28XX_R10_VINMODE 0x10 -#define EM28XX_R11_VINCTRL 0x11 -#define EM28XX_R12_VINENABLE 0x12 /* */ - -#define EM28XX_R14_GAMMA 0x14 -#define EM28XX_R15_RGAIN 0x15 -#define EM28XX_R16_GGAIN 0x16 -#define EM28XX_R17_BGAIN 0x17 -#define EM28XX_R18_ROFFSET 0x18 -#define EM28XX_R19_GOFFSET 0x19 -#define EM28XX_R1A_BOFFSET 0x1a - -#define EM28XX_R1B_OFLOW 0x1b -#define EM28XX_R1C_HSTART 0x1c -#define EM28XX_R1D_VSTART 0x1d -#define EM28XX_R1E_CWIDTH 0x1e -#define EM28XX_R1F_CHEIGHT 0x1f - -#define EM28XX_R20_YGAIN 0x20 -#define EM28XX_R21_YOFFSET 0x21 -#define EM28XX_R22_UVGAIN 0x22 -#define EM28XX_R23_UOFFSET 0x23 -#define EM28XX_R24_VOFFSET 0x24 -#define EM28XX_R25_SHARPNESS 0x25 - -#define EM28XX_R26_COMPR 0x26 -#define EM28XX_R27_OUTFMT 0x27 - -#define EM28XX_R28_XMIN 0x28 -#define EM28XX_R29_XMAX 0x29 -#define EM28XX_R2A_YMIN 0x2a -#define EM28XX_R2B_YMAX 0x2b - -#define EM28XX_R30_HSCALELOW 0x30 -#define EM28XX_R31_HSCALEHIGH 0x31 -#define EM28XX_R32_VSCALELOW 0x32 -#define EM28XX_R33_VSCALEHIGH 0x33 - -#define EM28XX_R40_AC97LSB 0x40 -#define EM28XX_R41_AC97MSB 0x41 -#define EM28XX_R42_AC97ADDR 0x42 -#define EM28XX_R43_AC97BUSY 0x43 - -/* em202 registers */ -#define EM28XX_R02_MASTER_AC97 0x02 -#define EM28XX_R10_LINE_IN_AC97 0x10 -#define EM28XX_R14_VIDEO_AC97 0x14 - -/* register settings */ -#define EM2800_AUDIO_SRC_TUNER 0x0d -#define EM2800_AUDIO_SRC_LINE 0x0c -#define EM28XX_AUDIO_SRC_TUNER 0xc0 -#define EM28XX_AUDIO_SRC_LINE 0x80 - -/* FIXME: Need to be populated with the other chip ID's */ -enum em28xx_chip_id { - CHIP_ID_EM2860 = 34, - CHIP_ID_EM2883 = 36, -}; diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c deleted file mode 100644 index 49ab0629702..00000000000 --- a/drivers/media/video/em28xx/em28xx-video.c +++ /dev/null @@ -1,2301 +0,0 @@ -/* - em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB - video capture devices - - Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it> - Markus Rechberger <mrechberger@gmail.com> - Mauro Carvalho Chehab <mchehab@infradead.org> - Sascha Sommer <saschasommer@freenet.de> - - Some parts based on SN9C10x PC Camera Controllers GPL driver made - by Luca Risolia <luca.risolia@studio.unibo.it> - - 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 <linux/init.h> -#include <linux/list.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/bitmap.h> -#include <linux/usb.h> -#include <linux/i2c.h> -#include <linux/version.h> -#include <linux/mm.h> -#include <linux/mutex.h> - -#include "em28xx.h" -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> -#include <media/msp3400.h> -#include <media/tuner.h> - -#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \ - "Markus Rechberger <mrechberger@gmail.com>, " \ - "Mauro Carvalho Chehab <mchehab@infradead.org>, " \ - "Sascha Sommer <saschasommer@freenet.de>" - -#define DRIVER_NAME "em28xx" -#define DRIVER_DESC "Empia em28xx based USB video device driver" -#define EM28XX_VERSION_CODE KERNEL_VERSION(0, 1, 0) - -#define em28xx_videodbg(fmt, arg...) do {\ - if (video_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) - -static unsigned int isoc_debug; -module_param(isoc_debug, int, 0644); -MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]"); - -#define em28xx_isocdbg(fmt, arg...) \ -do {\ - if (isoc_debug) { \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); \ - } \ - } while (0) - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -static LIST_HEAD(em28xx_devlist); - -static unsigned int card[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET }; - -module_param_array(card, int, NULL, 0444); -module_param_array(video_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); -MODULE_PARM_DESC(card, "card type"); -MODULE_PARM_DESC(video_nr, "video device numbers"); -MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); -MODULE_PARM_DESC(radio_nr, "radio device numbers"); - -static unsigned int video_debug; -module_param(video_debug, int, 0644); -MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); - -/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */ -static unsigned long em28xx_devused; - -/* supported controls */ -/* Common to all boards */ -static struct v4l2_queryctrl em28xx_qctrl[] = { - { - .id = V4L2_CID_AUDIO_VOLUME, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Volume", - .minimum = 0x0, - .maximum = 0x1f, - .step = 0x1, - .default_value = 0x1f, - .flags = 0, - }, { - .id = V4L2_CID_AUDIO_MUTE, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - .flags = 0, - } -}; - -static struct usb_driver em28xx_usb_driver; - -/* ------------------------------------------------------------------ - DMA and thread functions - ------------------------------------------------------------------*/ - -/* - * Announces that a buffer were filled and request the next - */ -static inline void buffer_filled(struct em28xx *dev, - struct em28xx_dmaqueue *dma_q, - struct em28xx_buffer *buf) -{ - /* Advice that buffer was filled */ - em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i); - buf->vb.state = VIDEOBUF_DONE; - buf->vb.field_count++; - do_gettimeofday(&buf->vb.ts); - - dev->isoc_ctl.buf = NULL; - - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); -} - -/* - * Identify the buffer header type and properly handles - */ -static void em28xx_copy_video(struct em28xx *dev, - struct em28xx_dmaqueue *dma_q, - struct em28xx_buffer *buf, - unsigned char *p, - unsigned char *outp, unsigned long len) -{ - void *fieldstart, *startwrite, *startread; - int linesdone, currlinedone, offset, lencopy, remain; - int bytesperline = dev->width << 1; - - if (dma_q->pos + len > buf->vb.size) - len = buf->vb.size - dma_q->pos; - - if (p[0] != 0x88 && p[0] != 0x22) { - em28xx_isocdbg("frame is not complete\n"); - len += 4; - } else - p += 4; - - startread = p; - remain = len; - - /* Interlaces frame */ - if (buf->top_field) - fieldstart = outp; - else - fieldstart = outp + bytesperline; - - linesdone = dma_q->pos / bytesperline; - currlinedone = dma_q->pos % bytesperline; - offset = linesdone * bytesperline * 2 + currlinedone; - startwrite = fieldstart + offset; - lencopy = bytesperline - currlinedone; - lencopy = lencopy > remain ? remain : lencopy; - - if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) { - em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n", - ((char *)startwrite + lencopy) - - ((char *)outp + buf->vb.size)); - lencopy = remain = (char *)outp + buf->vb.size - (char *)startwrite; - } - if (lencopy <= 0) - return; - memcpy(startwrite, startread, lencopy); - - remain -= lencopy; - - while (remain > 0) { - startwrite += lencopy + bytesperline; - startread += lencopy; - if (bytesperline > remain) - lencopy = remain; - else - lencopy = bytesperline; - - if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) { - em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n", - ((char *)startwrite + lencopy) - - ((char *)outp + buf->vb.size)); - lencopy = remain = (char *)outp + buf->vb.size - - (char *)startwrite; - } - if (lencopy <= 0) - break; - - memcpy(startwrite, startread, lencopy); - - remain -= lencopy; - } - - dma_q->pos += len; -} - -static inline void print_err_status(struct em28xx *dev, - int packet, int status) -{ - char *errmsg = "Unknown"; - - switch (status) { - case -ENOENT: - errmsg = "unlinked synchronuously"; - break; - case -ECONNRESET: - errmsg = "unlinked asynchronuously"; - break; - case -ENOSR: - errmsg = "Buffer error (overrun)"; - break; - case -EPIPE: - errmsg = "Stalled (device not responding)"; - break; - case -EOVERFLOW: - errmsg = "Babble (bad cable?)"; - break; - case -EPROTO: - errmsg = "Bit-stuff error (bad cable?)"; - break; - case -EILSEQ: - errmsg = "CRC/Timeout (could be anything)"; - break; - case -ETIME: - errmsg = "Device does not respond"; - break; - } - if (packet < 0) { - em28xx_isocdbg("URB status %d [%s].\n", status, errmsg); - } else { - em28xx_isocdbg("URB packet %d, status %d [%s].\n", - packet, status, errmsg); - } -} - -/* - * video-buf generic routine to get the next available buffer - */ -static inline void get_next_buf(struct em28xx_dmaqueue *dma_q, - struct em28xx_buffer **buf) -{ - struct em28xx *dev = container_of(dma_q, struct em28xx, vidq); - char *outp; - - if (list_empty(&dma_q->active)) { - em28xx_isocdbg("No active queue to serve\n"); - dev->isoc_ctl.buf = NULL; - *buf = NULL; - return; - } - - /* Get the next buffer */ - *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue); - - /* Cleans up buffer - Usefull for testing for frame/URB loss */ - outp = videobuf_to_vmalloc(&(*buf)->vb); - memset(outp, 0, (*buf)->vb.size); - - dev->isoc_ctl.buf = *buf; - - return; -} - -/* - * Controls the isoc copy of each urb packet - */ -static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb) -{ - struct em28xx_buffer *buf; - struct em28xx_dmaqueue *dma_q = urb->context; - unsigned char *outp = NULL; - int i, len = 0, rc = 1; - unsigned char *p; - - if (!dev) - return 0; - - if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED)) - return 0; - - if (urb->status < 0) { - print_err_status(dev, -1, urb->status); - if (urb->status == -ENOENT) - return 0; - } - - buf = dev->isoc_ctl.buf; - if (buf != NULL) - outp = videobuf_to_vmalloc(&buf->vb); - - for (i = 0; i < urb->number_of_packets; i++) { - int status = urb->iso_frame_desc[i].status; - - if (status < 0) { - print_err_status(dev, i, status); - if (urb->iso_frame_desc[i].status != -EPROTO) - continue; - } - - len = urb->iso_frame_desc[i].actual_length - 4; - - if (urb->iso_frame_desc[i].actual_length <= 0) { - /* em28xx_isocdbg("packet %d is empty",i); - spammy */ - continue; - } - if (urb->iso_frame_desc[i].actual_length > - dev->max_pkt_size) { - em28xx_isocdbg("packet bigger than packet size"); - continue; - } - - p = urb->transfer_buffer + urb->iso_frame_desc[i].offset; - - /* FIXME: incomplete buffer checks where removed to make - logic simpler. Impacts of those changes should be evaluated - */ - if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) { - em28xx_isocdbg("VBI HEADER!!!\n"); - /* FIXME: Should add vbi copy */ - continue; - } - if (p[0] == 0x22 && p[1] == 0x5a) { - em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2], - len, (p[2] & 1)? "odd" : "even"); - - if (!(p[2] & 1)) { - if (buf != NULL) - buffer_filled(dev, dma_q, buf); - get_next_buf(dma_q, &buf); - if (buf == NULL) - outp = NULL; - else - outp = videobuf_to_vmalloc(&buf->vb); - } - - if (buf != NULL) { - if (p[2] & 1) - buf->top_field = 0; - else - buf->top_field = 1; - } - - dma_q->pos = 0; - } - if (buf != NULL) - em28xx_copy_video(dev, dma_q, buf, p, outp, len); - } - return rc; -} - -/* ------------------------------------------------------------------ - Videobuf operations - ------------------------------------------------------------------*/ - -static int -buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) -{ - struct em28xx_fh *fh = vq->priv_data; - struct em28xx *dev = fh->dev; - struct v4l2_frequency f; - - *size = 16 * fh->dev->width * fh->dev->height >> 3; - if (0 == *count) - *count = EM28XX_DEF_BUF; - - if (*count < EM28XX_MIN_BUF) - *count = EM28XX_MIN_BUF; - - /* Ask tuner to go to analog mode */ - memset(&f, 0, sizeof(f)); - f.frequency = dev->ctl_freq; - - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f); - - return 0; -} - -/* This is called *without* dev->slock held; please keep it that way */ -static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf) -{ - struct em28xx_fh *fh = vq->priv_data; - struct em28xx *dev = fh->dev; - unsigned long flags = 0; - if (in_interrupt()) - BUG(); - - /* We used to wait for the buffer to finish here, but this didn't work - because, as we were keeping the state as VIDEOBUF_QUEUED, - videobuf_queue_cancel marked it as finished for us. - (Also, it could wedge forever if the hardware was misconfigured.) - - This should be safe; by the time we get here, the buffer isn't - queued anymore. If we ever start marking the buffers as - VIDEOBUF_ACTIVE, it won't be, though. - */ - spin_lock_irqsave(&dev->slock, flags); - if (dev->isoc_ctl.buf == buf) - dev->isoc_ctl.buf = NULL; - spin_unlock_irqrestore(&dev->slock, flags); - - videobuf_vmalloc_free(&buf->vb); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -static int -buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, - enum v4l2_field field) -{ - struct em28xx_fh *fh = vq->priv_data; - struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); - struct em28xx *dev = fh->dev; - int rc = 0, urb_init = 0; - - /* FIXME: It assumes depth = 16 */ - /* The only currently supported format is 16 bits/pixel */ - buf->vb.size = 16 * dev->width * dev->height >> 3; - - if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) - return -EINVAL; - - buf->vb.width = dev->width; - buf->vb.height = dev->height; - buf->vb.field = field; - - if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { - rc = videobuf_iolock(vq, &buf->vb, NULL); - if (rc < 0) - goto fail; - } - - if (!dev->isoc_ctl.num_bufs) - urb_init = 1; - - if (urb_init) { - rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS, - EM28XX_NUM_BUFS, dev->max_pkt_size, - em28xx_isoc_copy); - if (rc < 0) - goto fail; - } - - buf->vb.state = VIDEOBUF_PREPARED; - return 0; - -fail: - free_buffer(vq, buf); - return rc; -} - -static void -buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); - struct em28xx_fh *fh = vq->priv_data; - struct em28xx *dev = fh->dev; - struct em28xx_dmaqueue *vidq = &dev->vidq; - - buf->vb.state = VIDEOBUF_QUEUED; - list_add_tail(&buf->vb.queue, &vidq->active); - -} - -static void buffer_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) -{ - struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb); - struct em28xx_fh *fh = vq->priv_data; - struct em28xx *dev = (struct em28xx *)fh->dev; - - em28xx_isocdbg("em28xx: called buffer_release\n"); - - free_buffer(vq, buf); -} - -static struct videobuf_queue_ops em28xx_video_qops = { - .buf_setup = buffer_setup, - .buf_prepare = buffer_prepare, - .buf_queue = buffer_queue, - .buf_release = buffer_release, -}; - -/********************* v4l2 interface **************************************/ - -/* - * em28xx_config() - * inits registers with sane defaults - */ -static int em28xx_config(struct em28xx *dev) -{ - - /* Sets I2C speed to 100 KHz */ - if (!dev->is_em2800) - em28xx_write_regs_req(dev, 0x00, 0x06, "\x40", 1); - - /* enable vbi capturing */ - -/* em28xx_write_regs_req(dev, 0x00, 0x0e, "\xC0", 1); audio register */ -/* em28xx_write_regs_req(dev, 0x00, 0x0f, "\x80", 1); clk register */ - em28xx_write_regs_req(dev, 0x00, 0x11, "\x51", 1); - - dev->mute = 1; /* maybe not the right place... */ - dev->volume = 0x1f; - - em28xx_outfmt_set_yuv422(dev); - em28xx_colorlevels_set_default(dev); - em28xx_compression_disable(dev); - - return 0; -} - -/* - * em28xx_config_i2c() - * configure i2c attached devices - */ -static void em28xx_config_i2c(struct em28xx *dev) -{ - struct v4l2_routing route; - - route.input = INPUT(dev->ctl_input)->vmux; - route.output = 0; - em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL); - em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); - em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); -} - -static void video_mux(struct em28xx *dev, int index) -{ - struct v4l2_routing route; - - route.input = INPUT(index)->vmux; - route.output = 0; - dev->ctl_input = index; - dev->ctl_ainput = INPUT(index)->amux; - - em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route); - - if (dev->has_msp34xx) { - if (dev->i2s_speed) { - em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, - &dev->i2s_speed); - } - route.input = dev->ctl_ainput; - route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1); - /* Note: this is msp3400 specific */ - em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, - &route); - } - - em28xx_audio_analog_set(dev); -} - -/* Usage lock check functions */ -static int res_get(struct em28xx_fh *fh) -{ - struct em28xx *dev = fh->dev; - int rc = 0; - - /* This instance already has stream_on */ - if (fh->stream_on) - return rc; - - if (dev->stream_on) - return -EINVAL; - - mutex_lock(&dev->lock); - dev->stream_on = 1; - fh->stream_on = 1; - mutex_unlock(&dev->lock); - return rc; -} - -static int res_check(struct em28xx_fh *fh) -{ - return (fh->stream_on); -} - -static void res_free(struct em28xx_fh *fh) -{ - struct em28xx *dev = fh->dev; - - mutex_lock(&dev->lock); - fh->stream_on = 0; - dev->stream_on = 0; - mutex_unlock(&dev->lock); -} - -/* - * em28xx_get_ctrl() - * return the current saturation, brightness or contrast, mute state - */ -static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value = dev->mute; - return 0; - case V4L2_CID_AUDIO_VOLUME: - ctrl->value = dev->volume; - return 0; - default: - return -EINVAL; - } -} - -/* - * em28xx_set_ctrl() - * mute or set new saturation, brightness or contrast - */ -static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value != dev->mute) { - dev->mute = ctrl->value; - return em28xx_audio_analog_set(dev); - } - return 0; - case V4L2_CID_AUDIO_VOLUME: - dev->volume = ctrl->value; - return em28xx_audio_analog_set(dev); - default: - return -EINVAL; - } -} - -static int check_dev(struct em28xx *dev) -{ - if (dev->state & DEV_DISCONNECTED) { - em28xx_errdev("v4l2 ioctl: device not present\n"); - return -ENODEV; - } - - if (dev->state & DEV_MISCONFIGURED) { - em28xx_errdev("v4l2 ioctl: device is misconfigured; " - "close and open it again\n"); - return -EIO; - } - return 0; -} - -static void get_scale(struct em28xx *dev, - unsigned int width, unsigned int height, - unsigned int *hscale, unsigned int *vscale) -{ - unsigned int maxw = norm_maxw(dev); - unsigned int maxh = norm_maxh(dev); - - *hscale = (((unsigned long)maxw) << 12) / width - 4096L; - if (*hscale >= 0x4000) - *hscale = 0x3fff; - - *vscale = (((unsigned long)maxh) << 12) / height - 4096L; - if (*vscale >= 0x4000) - *vscale = 0x3fff; -} - -/* ------------------------------------------------------------------ - IOCTL vidioc handling - ------------------------------------------------------------------*/ - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - mutex_lock(&dev->lock); - - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - f->fmt.pix.bytesperline = dev->width * 2; - f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - - /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ - f->fmt.pix.field = dev->interlaced ? - V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int width = f->fmt.pix.width; - int height = f->fmt.pix.height; - unsigned int maxw = norm_maxw(dev); - unsigned int maxh = norm_maxh(dev); - unsigned int hscale, vscale; - - /* width must even because of the YUYV format - height must be even because of interlacing */ - height &= 0xfffe; - width &= 0xfffe; - - if (height < 32) - height = 32; - if (height > maxh) - height = maxh; - if (width < 48) - width = 48; - if (width > maxw) - width = maxw; - - mutex_lock(&dev->lock); - - if (dev->is_em2800) { - /* the em2800 can only scale down to 50% */ - if (height % (maxh / 2)) - height = maxh; - if (width % (maxw / 2)) - width = maxw; - /* according to empiatech support */ - /* the MaxPacketSize is to small to support */ - /* framesizes larger than 640x480 @ 30 fps */ - /* or 640x576 @ 25 fps. As this would cut */ - /* of a part of the image we prefer */ - /* 360x576 or 360x480 for now */ - if (width == maxw && height == maxh) - width /= 2; - } - - get_scale(dev, width, height, &hscale, &vscale); - - width = (((unsigned long)maxw) << 12) / (hscale + 4096L); - height = (((unsigned long)maxh) << 12) / (vscale + 4096L); - - f->fmt.pix.width = width; - f->fmt.pix.height = height; - f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - f->fmt.pix.bytesperline = width * 2; - f->fmt.pix.sizeimage = width * 2 * height; - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.field = V4L2_FIELD_INTERLACED; - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - vidioc_try_fmt_vid_cap(file, priv, f); - - mutex_lock(&dev->lock); - - if (videobuf_queue_is_busy(&fh->vb_vidq)) { - em28xx_errdev("%s queue busy\n", __func__); - rc = -EBUSY; - goto out; - } - - if (dev->stream_on && !fh->stream_on) { - em28xx_errdev("%s device in use by another fh\n", __func__); - rc = -EBUSY; - goto out; - } - - /* set new image size */ - dev->width = f->fmt.pix.width; - dev->height = f->fmt.pix.height; - get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); - - em28xx_set_alternate(dev); - em28xx_resolution_set(dev); - - rc = 0; - -out: - mutex_unlock(&dev->lock); - return rc; -} - -static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - struct v4l2_format f; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - mutex_lock(&dev->lock); - dev->norm = *norm; - mutex_unlock(&dev->lock); - - /* Adjusts width/height, if needed */ - f.fmt.pix.width = dev->width; - f.fmt.pix.height = dev->height; - vidioc_try_fmt_vid_cap(file, priv, &f); - - mutex_lock(&dev->lock); - - /* set new image size */ - dev->width = f.fmt.pix.width; - dev->height = f.fmt.pix.height; - get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale); - - em28xx_resolution_set(dev); - em28xx_i2c_call_clients(dev, VIDIOC_S_STD, &dev->norm); - - mutex_unlock(&dev->lock); - return 0; -} - -static const char *iname[] = { - [EM28XX_VMUX_COMPOSITE1] = "Composite1", - [EM28XX_VMUX_COMPOSITE2] = "Composite2", - [EM28XX_VMUX_COMPOSITE3] = "Composite3", - [EM28XX_VMUX_COMPOSITE4] = "Composite4", - [EM28XX_VMUX_SVIDEO] = "S-Video", - [EM28XX_VMUX_TELEVISION] = "Television", - [EM28XX_VMUX_CABLE] = "Cable TV", - [EM28XX_VMUX_DVB] = "DVB", - [EM28XX_VMUX_DEBUG] = "for debug only", -}; - -static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - unsigned int n; - - n = i->index; - if (n >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(n)->type) - return -EINVAL; - - i->index = n; - i->type = V4L2_INPUT_TYPE_CAMERA; - - strcpy(i->name, iname[INPUT(n)->type]); - - if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) || - (EM28XX_VMUX_CABLE == INPUT(n)->type)) - i->type = V4L2_INPUT_TYPE_TUNER; - - i->std = dev->vdev->tvnorms; - - return 0; -} - -static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - *i = dev->ctl_input; - - return 0; -} - -static int vidioc_s_input(struct file *file, void *priv, unsigned int i) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (i >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(i)->type) - return -EINVAL; - - mutex_lock(&dev->lock); - - video_mux(dev, i); - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - unsigned int index = a->index; - - if (a->index > 1) - return -EINVAL; - - index = dev->ctl_ainput; - - if (index == 0) - strcpy(a->name, "Television"); - else - strcpy(a->name, "Line In"); - - a->capability = V4L2_AUDCAP_STEREO; - a->index = index; - - return 0; -} - -static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - if (a->index != dev->ctl_ainput) - return -EINVAL; - - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int id = qc->id; - int i; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - memset(qc, 0, sizeof(*qc)); - - qc->id = id; - - if (!dev->has_msp34xx) { - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (qc->id && qc->id == em28xx_qctrl[i].id) { - memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); - return 0; - } - } - } - mutex_lock(&dev->lock); - em28xx_i2c_call_clients(dev, VIDIOC_QUERYCTRL, qc); - mutex_unlock(&dev->lock); - - if (qc->type) - return 0; - else - return -EINVAL; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - mutex_lock(&dev->lock); - - if (!dev->has_msp34xx) - rc = em28xx_get_ctrl(dev, ctrl); - else - rc = -EINVAL; - - if (rc == -EINVAL) { - em28xx_i2c_call_clients(dev, VIDIOC_G_CTRL, ctrl); - rc = 0; - } - - mutex_unlock(&dev->lock); - return rc; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - u8 i; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - mutex_lock(&dev->lock); - - if (dev->has_msp34xx) - em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); - else { - rc = 1; - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (ctrl->id == em28xx_qctrl[i].id) { - if (ctrl->value < em28xx_qctrl[i].minimum || - ctrl->value > em28xx_qctrl[i].maximum) { - rc = -ERANGE; - break; - } - - rc = em28xx_set_ctrl(dev, ctrl); - break; - } - } - } - - /* Control not found - try to send it to the attached devices */ - if (rc == 1) { - em28xx_i2c_call_clients(dev, VIDIOC_S_CTRL, ctrl); - rc = 0; - } - - mutex_unlock(&dev->lock); - return rc; -} - -static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != t->index) - return -EINVAL; - - strcpy(t->name, "Tuner"); - - mutex_lock(&dev->lock); - - em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != t->index) - return -EINVAL; - - mutex_lock(&dev->lock); - - em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); - - mutex_unlock(&dev->lock); - return 0; -} - -static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; - - return 0; -} - -static int vidioc_s_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (0 != f->tuner) - return -EINVAL; - - if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) - return -EINVAL; - if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) - return -EINVAL; - - mutex_lock(&dev->lock); - - dev->ctl_freq = f->frequency; - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); - - mutex_unlock(&dev->lock); - return 0; -} - -#ifdef CONFIG_VIDEO_ADV_DEBUG -static int em28xx_reg_len(int reg) -{ - switch (reg) { - case EM28XX_R40_AC97LSB: - case EM28XX_R30_HSCALELOW: - case EM28XX_R32_VSCALELOW: - return 2; - default: - return 1; - } -} - -static int vidioc_g_register(struct file *file, void *priv, - struct v4l2_register *reg) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int ret; - - if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) - return -EINVAL; - - if (em28xx_reg_len(reg->reg) == 1) { - ret = em28xx_read_reg(dev, reg->reg); - if (ret < 0) - return ret; - - reg->val = ret; - } else { - __le64 val = 0; - ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS, - reg->reg, (char *)&val, 2); - if (ret < 0) - return ret; - - reg->val = le64_to_cpu(val); - } - - return 0; -} - -static int vidioc_s_register(struct file *file, void *priv, - struct v4l2_register *reg) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - __le64 buf; - - buf = cpu_to_le64(reg->val); - - return em28xx_write_regs(dev, reg->reg, (char *)&buf, - em28xx_reg_len(reg->reg)); -} -#endif - - -static int vidioc_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *cc) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - cc->bounds.left = 0; - cc->bounds.top = 0; - cc->bounds.width = dev->width; - cc->bounds.height = dev->height; - cc->defrect = cc->bounds; - cc->pixelaspect.numerator = 54; /* 4:3 FIXME: remove magic numbers */ - cc->pixelaspect.denominator = 59; - - return 0; -} - -static int vidioc_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - - if (unlikely(res_get(fh) < 0)) - return -EBUSY; - - return (videobuf_streamon(&fh->vb_vidq)); -} - -static int vidioc_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (type != fh->type) - return -EINVAL; - - videobuf_streamoff(&fh->vb_vidq); - res_free(fh); - - return 0; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - - strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); - strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); - strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); - - cap->version = EM28XX_VERSION_CODE; - - cap->capabilities = - V4L2_CAP_SLICED_VBI_CAPTURE | - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - - if (dev->tuner_type != TUNER_ABSENT) - cap->capabilities |= V4L2_CAP_TUNER; - - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *fmtd) -{ - if (fmtd->index != 0) - return -EINVAL; - - fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - strcpy(fmtd->description, "Packed YUY2"); - fmtd->pixelformat = V4L2_PIX_FMT_YUYV; - memset(fmtd->reserved, 0, sizeof(fmtd->reserved)); - - return 0; -} - -/* Sliced VBI ioctls */ -static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - mutex_lock(&dev->lock); - - f->fmt.sliced.service_set = 0; - - em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); - - if (f->fmt.sliced.service_set == 0) - rc = -EINVAL; - - mutex_unlock(&dev->lock); - return rc; -} - -static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - mutex_lock(&dev->lock); - em28xx_i2c_call_clients(dev, VIDIOC_G_FMT, f); - mutex_unlock(&dev->lock); - - if (f->fmt.sliced.service_set == 0) - return -EINVAL; - - return 0; -} - - -static int vidioc_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return (videobuf_reqbufs(&fh->vb_vidq, rb)); -} - -static int vidioc_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return (videobuf_querybuf(&fh->vb_vidq, b)); -} - -static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return (videobuf_qbuf(&fh->vb_vidq, b)); -} - -static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct em28xx_fh *fh = priv; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - return (videobuf_dqbuf(&fh->vb_vidq, b, - file->f_flags & O_NONBLOCK)); -} - -#ifdef CONFIG_VIDEO_V4L1_COMPAT -static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) -{ - struct em28xx_fh *fh = priv; - - return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); -} -#endif - - -/* ----------------------------------------------------------- */ -/* RADIO ESPECIFIC IOCTLS */ -/* ----------------------------------------------------------- */ - -static int radio_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; - - strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); - strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); - strlcpy(cap->bus_info, dev->udev->dev.bus_id, sizeof(cap->bus_info)); - - cap->version = EM28XX_VERSION_CODE; - cap->capabilities = V4L2_CAP_TUNER; - return 0; -} - -static int radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; - - if (unlikely(t->index > 0)) - return -EINVAL; - - strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; - - em28xx_i2c_call_clients(dev, VIDIOC_G_TUNER, t); - return 0; -} - -static int radio_enum_input(struct file *file, void *priv, - struct v4l2_input *i) -{ - if (i->index != 0) - return -EINVAL; - strcpy(i->name, "Radio"); - i->type = V4L2_INPUT_TYPE_TUNER; - - return 0; -} - -static int radio_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - if (unlikely(a->index)) - return -EINVAL; - - strcpy(a->name, "Radio"); - return 0; -} - -static int radio_s_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) -{ - struct em28xx *dev = ((struct em28xx_fh *)priv)->dev; - - if (0 != t->index) - return -EINVAL; - - em28xx_i2c_call_clients(dev, VIDIOC_S_TUNER, t); - - return 0; -} - -static int radio_s_audio(struct file *file, void *fh, - struct v4l2_audio *a) -{ - return 0; -} - -static int radio_s_input(struct file *file, void *fh, unsigned int i) -{ - return 0; -} - -static int radio_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *qc) -{ - int i; - - if (qc->id < V4L2_CID_BASE || - qc->id >= V4L2_CID_LASTP1) - return -EINVAL; - - for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) { - if (qc->id && qc->id == em28xx_qctrl[i].id) { - memcpy(qc, &(em28xx_qctrl[i]), sizeof(*qc)); - return 0; - } - } - - return -EINVAL; -} - -/* - * em28xx_v4l2_open() - * inits the device and starts isoc transfer - */ -static int em28xx_v4l2_open(struct inode *inode, struct file *filp) -{ - int minor = iminor(inode); - int errCode = 0, radio = 0; - struct em28xx *h, *dev = NULL; - struct em28xx_fh *fh; - enum v4l2_buf_type fh_type = 0; - - list_for_each_entry(h, &em28xx_devlist, devlist) { - if (h->vdev->minor == minor) { - dev = h; - fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - if (h->vbi_dev->minor == minor) { - dev = h; - fh_type = V4L2_BUF_TYPE_VBI_CAPTURE; - } - if (h->radio_dev && - h->radio_dev->minor == minor) { - radio = 1; - dev = h; - } - } - if (NULL == dev) - return -ENODEV; - - em28xx_videodbg("open minor=%d type=%s users=%d\n", - minor, v4l2_type_names[fh_type], dev->users); - - - fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); - if (!fh) { - em28xx_errdev("em28xx-video.c: Out of memory?!\n"); - return -ENOMEM; - } - mutex_lock(&dev->lock); - fh->dev = dev; - fh->radio = radio; - fh->type = fh_type; - filp->private_data = fh; - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) { - dev->width = norm_maxw(dev); - dev->height = norm_maxh(dev); - dev->hscale = 0; - dev->vscale = 0; - - em28xx_set_mode(dev, EM28XX_ANALOG_MODE); - em28xx_set_alternate(dev); - em28xx_resolution_set(dev); - - /* Needed, since GPIO might have disabled power of - some i2c device - */ - em28xx_config_i2c(dev); - - } - if (fh->radio) { - em28xx_videodbg("video_open: setting radio device\n"); - em28xx_i2c_call_clients(dev, AUDC_SET_RADIO, NULL); - } - - dev->users++; - - videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops, - NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, - sizeof(struct em28xx_buffer), fh); - - mutex_unlock(&dev->lock); - - return errCode; -} - -/* - * em28xx_realease_resources() - * unregisters the v4l2,i2c and usb devices - * called when the device gets disconected or at module unload -*/ -static void em28xx_release_resources(struct em28xx *dev) -{ - - /*FIXME: I2C IR should be disconnected */ - - em28xx_info("V4L2 devices /dev/video%d and /dev/vbi%d deregistered\n", - dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, - dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); - list_del(&dev->devlist); - if (dev->sbutton_input_dev) - em28xx_deregister_snapshot_button(dev); - if (dev->radio_dev) { - if (-1 != dev->radio_dev->minor) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } - if (dev->vbi_dev) { - if (-1 != dev->vbi_dev->minor) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; - } - if (dev->vdev) { - if (-1 != dev->vdev->minor) - video_unregister_device(dev->vdev); - else - video_device_release(dev->vdev); - dev->vdev = NULL; - } - em28xx_i2c_unregister(dev); - usb_put_dev(dev->udev); - - /* Mark device as unused */ - em28xx_devused &= ~(1<<dev->devno); -} - -/* - * em28xx_v4l2_close() - * stops streaming and deallocates all resources allocated by the v4l2 - * calls and ioctls - */ -static int em28xx_v4l2_close(struct inode *inode, struct file *filp) -{ - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - int errCode; - - em28xx_videodbg("users=%d\n", dev->users); - - - if (res_check(fh)) - res_free(fh); - - mutex_lock(&dev->lock); - - if (dev->users == 1) { - videobuf_stop(&fh->vb_vidq); - videobuf_mmap_free(&fh->vb_vidq); - - /* the device is already disconnect, - free the remaining resources */ - if (dev->state & DEV_DISCONNECTED) { - em28xx_release_resources(dev); - mutex_unlock(&dev->lock); - kfree(dev); - return 0; - } - - /* do this before setting alternate! */ - em28xx_uninit_isoc(dev); - em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED); - - /* set alternate 0 */ - dev->alt = 0; - em28xx_videodbg("setting alternate 0\n"); - errCode = usb_set_interface(dev->udev, 0, 0); - if (errCode < 0) { - em28xx_errdev("cannot change alternate number to " - "0 (error=%i)\n", errCode); - } - } - kfree(fh); - dev->users--; - wake_up_interruptible_nr(&dev->open, 1); - mutex_unlock(&dev->lock); - return 0; -} - -/* - * em28xx_v4l2_read() - * will allocate buffers when called for the first time - */ -static ssize_t -em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count, - loff_t *pos) -{ - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - /* FIXME: read() is not prepared to allow changing the video - resolution while streaming. Seems a bug at em28xx_set_fmt - */ - - if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - if (unlikely(res_get(fh))) - return -EBUSY; - - return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0, - filp->f_flags & O_NONBLOCK); - } - return 0; -} - -/* - * em28xx_v4l2_poll() - * will allocate buffers when called for the first time - */ -static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) -{ - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - int rc; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - if (unlikely(res_get(fh) < 0)) - return POLLERR; - - if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) - return POLLERR; - - return videobuf_poll_stream(filp, &fh->vb_vidq, wait); -} - -/* - * em28xx_v4l2_mmap() - */ -static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct em28xx_fh *fh = filp->private_data; - struct em28xx *dev = fh->dev; - int rc; - - if (unlikely(res_get(fh) < 0)) - return -EBUSY; - - rc = check_dev(dev); - if (rc < 0) - return rc; - - rc = videobuf_mmap_mapper(&fh->vb_vidq, vma); - - em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n", - (unsigned long)vma->vm_start, - (unsigned long)vma->vm_end-(unsigned long)vma->vm_start, - rc); - - return rc; -} - -static const struct file_operations em28xx_v4l_fops = { - .owner = THIS_MODULE, - .open = em28xx_v4l2_open, - .release = em28xx_v4l2_close, - .read = em28xx_v4l2_read, - .poll = em28xx_v4l2_poll, - .mmap = em28xx_v4l2_mmap, - .ioctl = video_ioctl2, - .llseek = no_llseek, - .compat_ioctl = v4l_compat_ioctl32, -}; - -static const struct v4l2_ioctl_ops video_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_cropcap = vidioc_cropcap, - - .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, - .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, - .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap, - - .vidioc_reqbufs = vidioc_reqbufs, - .vidioc_querybuf = vidioc_querybuf, - .vidioc_qbuf = vidioc_qbuf, - .vidioc_dqbuf = vidioc_dqbuf, - .vidioc_s_std = vidioc_s_std, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_streamon = vidioc_streamon, - .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif -#ifdef CONFIG_VIDEO_V4L1_COMPAT - .vidiocgmbuf = vidiocgmbuf, -#endif -}; - -static const struct video_device em28xx_video_template = { - .fops = &em28xx_v4l_fops, - .release = video_device_release, - .ioctl_ops = &video_ioctl_ops, - - .minor = -1, - - .tvnorms = V4L2_STD_ALL, - .current_norm = V4L2_STD_PAL, -}; - -static const struct file_operations radio_fops = { - .owner = THIS_MODULE, - .open = em28xx_v4l2_open, - .release = em28xx_v4l2_close, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; - -static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, - .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, - .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, -#ifdef CONFIG_VIDEO_ADV_DEBUG - .vidioc_g_register = vidioc_g_register, - .vidioc_s_register = vidioc_s_register, -#endif -}; - -static struct video_device em28xx_radio_template = { - .name = "em28xx-radio", - .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, - .minor = -1, -}; - -/******************************** usb interface ******************************/ - - -static LIST_HEAD(em28xx_extension_devlist); -static DEFINE_MUTEX(em28xx_extension_devlist_lock); - -int em28xx_register_extension(struct em28xx_ops *ops) -{ - struct em28xx *dev = NULL; - - mutex_lock(&em28xx_extension_devlist_lock); - list_add_tail(&ops->next, &em28xx_extension_devlist); - list_for_each_entry(dev, &em28xx_devlist, devlist) { - if (dev) - ops->init(dev); - } - printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name); - mutex_unlock(&em28xx_extension_devlist_lock); - return 0; -} -EXPORT_SYMBOL(em28xx_register_extension); - -void em28xx_unregister_extension(struct em28xx_ops *ops) -{ - struct em28xx *dev = NULL; - - list_for_each_entry(dev, &em28xx_devlist, devlist) { - if (dev) - ops->fini(dev); - } - - mutex_lock(&em28xx_extension_devlist_lock); - printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); - list_del(&ops->next); - mutex_unlock(&em28xx_extension_devlist_lock); -} -EXPORT_SYMBOL(em28xx_unregister_extension); - -static struct video_device *em28xx_vdev_init(struct em28xx *dev, - const struct video_device *template, - const char *type_name) -{ - struct video_device *vfd; - - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->minor = -1; - vfd->parent = &dev->udev->dev; - vfd->release = video_device_release; - vfd->debug = video_debug; - - snprintf(vfd->name, sizeof(vfd->name), "%s %s", - dev->name, type_name); - - return vfd; -} - - -/* - * em28xx_init_dev() - * allocates and inits the device structs, registers i2c bus and v4l device - */ -static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, - int minor) -{ - struct em28xx_ops *ops = NULL; - struct em28xx *dev = *devhandle; - int retval = -ENOMEM; - int errCode; - unsigned int maxh, maxw; - - dev->udev = udev; - mutex_init(&dev->lock); - spin_lock_init(&dev->slock); - init_waitqueue_head(&dev->open); - init_waitqueue_head(&dev->wait_frame); - init_waitqueue_head(&dev->wait_stream); - - dev->em28xx_write_regs = em28xx_write_regs; - dev->em28xx_read_reg = em28xx_read_reg; - dev->em28xx_read_reg_req_len = em28xx_read_reg_req_len; - dev->em28xx_write_regs_req = em28xx_write_regs_req; - dev->em28xx_read_reg_req = em28xx_read_reg_req; - dev->is_em2800 = em28xx_boards[dev->model].is_em2800; - - em28xx_pre_card_setup(dev); - - errCode = em28xx_config(dev); - if (errCode) { - em28xx_errdev("error configuring device\n"); - em28xx_devused &= ~(1<<dev->devno); - kfree(dev); - return -ENOMEM; - } - - /* register i2c bus */ - em28xx_i2c_register(dev); - - /* Do board specific init and eeprom reading */ - em28xx_card_setup(dev); - - /* Configure audio */ - em28xx_audio_analog_set(dev); - - /* configure the device */ - em28xx_config_i2c(dev); - - /* set default norm */ - dev->norm = em28xx_video_template.current_norm; - - maxw = norm_maxw(dev); - maxh = norm_maxh(dev); - - /* set default image size */ - dev->width = maxw; - dev->height = maxh; - dev->interlaced = EM28XX_INTERLACED_DEFAULT; - dev->hscale = 0; - dev->vscale = 0; - dev->ctl_input = 2; - - errCode = em28xx_config(dev); - - list_add_tail(&dev->devlist, &em28xx_devlist); - - /* allocate and fill video video_device struct */ - dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); - if (NULL == dev->vdev) { - em28xx_errdev("cannot allocate video_device.\n"); - goto fail_unreg; - } - - /* register v4l2 video video_device */ - retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, - video_nr[dev->devno]); - if (retval) { - em28xx_errdev("unable to register video device (error=%i).\n", - retval); - goto fail_unreg; - } - - /* Allocate and fill vbi video_device struct */ - dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi"); - /* register v4l2 vbi video_device */ - if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, - vbi_nr[dev->devno]) < 0) { - em28xx_errdev("unable to register vbi device\n"); - retval = -ENODEV; - goto fail_unreg; - } - - if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { - dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio"); - if (NULL == dev->radio_dev) { - em28xx_errdev("cannot allocate video_device.\n"); - goto fail_unreg; - } - retval = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, - radio_nr[dev->devno]); - if (retval < 0) { - em28xx_errdev("can't register radio device\n"); - goto fail_unreg; - } - em28xx_info("Registered radio device as /dev/radio%d\n", - dev->radio_dev->minor & 0x1f); - } - - /* init video dma queues */ - INIT_LIST_HEAD(&dev->vidq.active); - INIT_LIST_HEAD(&dev->vidq.queued); - - - if (dev->has_msp34xx) { - /* Send a reset to other chips via gpio */ - em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); - msleep(3); - em28xx_write_regs_req(dev, 0x00, 0x08, "\xff", 1); - msleep(3); - } - - video_mux(dev, 0); - - em28xx_info("V4L2 device registered as /dev/video%d and /dev/vbi%d\n", - dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN, - dev->vbi_dev->minor-MINOR_VFL_TYPE_VBI_MIN); - - mutex_lock(&em28xx_extension_devlist_lock); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - if (ops->id) - ops->init(dev); - } - } - mutex_unlock(&em28xx_extension_devlist_lock); - - return 0; - -fail_unreg: - em28xx_release_resources(dev); - mutex_unlock(&dev->lock); - kfree(dev); - return retval; -} - -#if defined(CONFIG_MODULES) && defined(MODULE) -static void request_module_async(struct work_struct *work) -{ - struct em28xx *dev = container_of(work, - struct em28xx, request_module_wk); - - if (dev->has_audio_class) - request_module("snd-usb-audio"); - else - request_module("em28xx-alsa"); - - if (dev->has_dvb) - request_module("em28xx-dvb"); -} - -static void request_modules(struct em28xx *dev) -{ - INIT_WORK(&dev->request_module_wk, request_module_async); - schedule_work(&dev->request_module_wk); -} -#else -#define request_modules(dev) -#endif /* CONFIG_MODULES */ - -/* - * em28xx_usb_probe() - * checks for supported devices - */ -static int em28xx_usb_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - const struct usb_endpoint_descriptor *endpoint; - struct usb_device *udev; - struct usb_interface *uif; - struct em28xx *dev = NULL; - int retval = -ENODEV; - int i, nr, ifnum; - - udev = usb_get_dev(interface_to_usbdev(interface)); - ifnum = interface->altsetting[0].desc.bInterfaceNumber; - - /* Check to see next free device and mark as used */ - nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS); - em28xx_devused |= 1<<nr; - - /* Don't register audio interfaces */ - if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n", - udev->descriptor.idVendor, - udev->descriptor.idProduct, - ifnum, - interface->altsetting[0].desc.bInterfaceClass); - - em28xx_devused &= ~(1<<nr); - return -ENODEV; - } - - em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n", - udev->descriptor.idVendor, - udev->descriptor.idProduct, - ifnum, - interface->altsetting[0].desc.bInterfaceClass); - - endpoint = &interface->cur_altsetting->endpoint[1].desc; - - /* check if the device has the iso in endpoint at the correct place */ - if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != - USB_ENDPOINT_XFER_ISOC) { - em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n"); - em28xx_devused &= ~(1<<nr); - return -ENODEV; - } - if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { - em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n"); - em28xx_devused &= ~(1<<nr); - return -ENODEV; - } - - if (nr >= EM28XX_MAXBOARDS) { - printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", - EM28XX_MAXBOARDS); - em28xx_devused &= ~(1<<nr); - return -ENOMEM; - } - - /* allocate memory for our device state and initialize it */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - em28xx_err(DRIVER_NAME ": out of memory!\n"); - em28xx_devused &= ~(1<<nr); - return -ENOMEM; - } - - snprintf(dev->name, 29, "em28xx #%d", nr); - dev->devno = nr; - dev->model = id->driver_info; - dev->alt = -1; - - /* Checks if audio is provided by some interface */ - for (i = 0; i < udev->config->desc.bNumInterfaces; i++) { - uif = udev->config->interface[i]; - if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - dev->has_audio_class = 1; - break; - } - } - - printk(KERN_INFO DRIVER_NAME " %s usb audio class\n", - dev->has_audio_class ? "Has" : "Doesn't have"); - - /* compute alternate max packet sizes */ - uif = udev->actconfig->interface[0]; - - dev->num_alt = uif->num_altsetting; - em28xx_info("Alternate settings: %i\n", dev->num_alt); -/* dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* */ - dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL); - - if (dev->alt_max_pkt_size == NULL) { - em28xx_errdev("out of memory!\n"); - em28xx_devused &= ~(1<<nr); - kfree(dev); - return -ENOMEM; - } - - for (i = 0; i < dev->num_alt ; i++) { - u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc. - wMaxPacketSize); - dev->alt_max_pkt_size[i] = - (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); - em28xx_info("Alternate setting %i, max size= %i\n", i, - dev->alt_max_pkt_size[i]); - } - - if ((card[nr] >= 0) && (card[nr] < em28xx_bcount)) - dev->model = card[nr]; - - /* allocate device struct */ - retval = em28xx_init_dev(&dev, udev, nr); - if (retval) - return retval; - - em28xx_info("Found %s\n", em28xx_boards[dev->model].name); - - /* save our data pointer in this interface device */ - usb_set_intfdata(interface, dev); - - request_modules(dev); - - return 0; -} - -/* - * em28xx_usb_disconnect() - * called when the device gets diconencted - * video device will be unregistered on v4l2_close in case it is still open - */ -static void em28xx_usb_disconnect(struct usb_interface *interface) -{ - struct em28xx *dev; - struct em28xx_ops *ops = NULL; - - dev = usb_get_intfdata(interface); - usb_set_intfdata(interface, NULL); - - if (!dev) - return; - - em28xx_info("disconnecting %s\n", dev->vdev->name); - - /* wait until all current v4l2 io is finished then deallocate - resources */ - mutex_lock(&dev->lock); - - wake_up_interruptible_all(&dev->open); - - if (dev->users) { - em28xx_warn - ("device /dev/video%d is open! Deregistration and memory " - "deallocation are deferred on close.\n", - dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); - - dev->state |= DEV_MISCONFIGURED; - em28xx_uninit_isoc(dev); - dev->state |= DEV_DISCONNECTED; - wake_up_interruptible(&dev->wait_frame); - wake_up_interruptible(&dev->wait_stream); - } else { - dev->state |= DEV_DISCONNECTED; - em28xx_release_resources(dev); - } - mutex_unlock(&dev->lock); - - mutex_lock(&em28xx_extension_devlist_lock); - if (!list_empty(&em28xx_extension_devlist)) { - list_for_each_entry(ops, &em28xx_extension_devlist, next) { - ops->fini(dev); - } - } - mutex_unlock(&em28xx_extension_devlist_lock); - - if (!dev->users) { - kfree(dev->alt_max_pkt_size); - kfree(dev); - } -} - -static struct usb_driver em28xx_usb_driver = { - .name = "em28xx", - .probe = em28xx_usb_probe, - .disconnect = em28xx_usb_disconnect, - .id_table = em28xx_id_table, -}; - -static int __init em28xx_module_init(void) -{ - int result; - - printk(KERN_INFO DRIVER_NAME " v4l2 driver version %d.%d.%d loaded\n", - (EM28XX_VERSION_CODE >> 16) & 0xff, - (EM28XX_VERSION_CODE >> 8) & 0xff, EM28XX_VERSION_CODE & 0xff); -#ifdef SNAPSHOT - printk(KERN_INFO DRIVER_NAME " snapshot date %04d-%02d-%02d\n", - SNAPSHOT / 10000, (SNAPSHOT / 100) % 100, SNAPSHOT % 100); -#endif - - /* register this driver with the USB subsystem */ - result = usb_register(&em28xx_usb_driver); - if (result) - em28xx_err(DRIVER_NAME - " usb_register failed. Error number %d.\n", result); - - return result; -} - -static void __exit em28xx_module_exit(void) -{ - /* deregister this driver with the USB subsystem */ - usb_deregister(&em28xx_usb_driver); -} - -module_init(em28xx_module_init); -module_exit(em28xx_module_exit); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h deleted file mode 100644 index 9a331074868..00000000000 --- a/drivers/media/video/em28xx/em28xx.h +++ /dev/null @@ -1,646 +0,0 @@ -/* - em28xx.h - driver for Empia EM2800/EM2820/2840 USB video capture devices - - Copyright (C) 2005 Markus Rechberger <mrechberger@gmail.com> - Ludovico Cavedon <cavedon@sssup.it> - Mauro Carvalho Chehab <mchehab@infradead.org> - - Based on the em2800 driver from Sascha Sommer <saschasommer@freenet.de> - - 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. - */ - -#ifndef _EM28XX_H -#define _EM28XX_H - -#include <linux/videodev2.h> -#include <media/videobuf-vmalloc.h> - -#include <linux/i2c.h> -#include <linux/mutex.h> -#include <media/ir-kbd-i2c.h> -#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE) -#include <media/videobuf-dvb.h> -#endif -#include "tuner-xc2028.h" -#include "em28xx-reg.h" - -/* Boards supported by driver */ -#define EM2800_BOARD_UNKNOWN 0 -#define EM2820_BOARD_UNKNOWN 1 -#define EM2820_BOARD_TERRATEC_CINERGY_250 2 -#define EM2820_BOARD_PINNACLE_USB_2 3 -#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4 -#define EM2820_BOARD_MSI_VOX_USB_2 5 -#define EM2800_BOARD_TERRATEC_CINERGY_200 6 -#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7 -#define EM2800_BOARD_KWORLD_USB2800 8 -#define EM2820_BOARD_PINNACLE_DVC_90 9 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10 -#define EM2880_BOARD_TERRATEC_HYBRID_XS 11 -#define EM2820_BOARD_KWORLD_PVRTV2800RF 12 -#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 -#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 -#define EM2800_BOARD_VGEAR_POCKETTV 15 -#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16 -#define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 -#define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA 19 -#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20 -#define EM2800_BOARD_GRABBEEX_USB2800 21 -#define EM2750_BOARD_UNKNOWN 22 -#define EM2750_BOARD_DLCW_130 23 -#define EM2820_BOARD_DLINK_USB_TV 24 -#define EM2820_BOARD_GADMEI_UTV310 25 -#define EM2820_BOARD_HERCULES_SMART_TV_USB2 26 -#define EM2820_BOARD_PINNACLE_USB_2_FM1216ME 27 -#define EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE 28 -#define EM2820_BOARD_PINNACLE_DVC_100 29 -#define EM2820_BOARD_VIDEOLOGY_20K14XUSB 30 -#define EM2821_BOARD_USBGEAR_VD204 31 -#define EM2821_BOARD_SUPERCOMP_USB_2 32 -#define EM2821_BOARD_PROLINK_PLAYTV_USB2 33 -#define EM2860_BOARD_TERRATEC_HYBRID_XS 34 -#define EM2860_BOARD_TYPHOON_DVD_MAKER 35 -#define EM2860_BOARD_NETGMBH_CAM 36 -#define EM2860_BOARD_GADMEI_UTV330 37 -#define EM2861_BOARD_YAKUMO_MOVIE_MIXER 38 -#define EM2861_BOARD_KWORLD_PVRTV_300U 39 -#define EM2861_BOARD_PLEXTOR_PX_TV100U 40 -#define EM2870_BOARD_KWORLD_350U 41 -#define EM2870_BOARD_KWORLD_355U 42 -#define EM2870_BOARD_TERRATEC_XS 43 -#define EM2870_BOARD_TERRATEC_XS_MT2060 44 -#define EM2870_BOARD_PINNACLE_PCTV_DVB 45 -#define EM2870_BOARD_COMPRO_VIDEOMATE 46 -#define EM2880_BOARD_KWORLD_DVB_305U 47 -#define EM2880_BOARD_KWORLD_DVB_310U 48 -#define EM2880_BOARD_MSI_DIGIVOX_AD 49 -#define EM2880_BOARD_MSI_DIGIVOX_AD_II 50 -#define EM2880_BOARD_TERRATEC_HYBRID_XS_FR 51 -#define EM2881_BOARD_DNT_DA2_HYBRID 52 -#define EM2881_BOARD_PINNACLE_HYBRID_PRO 53 -#define EM2882_BOARD_KWORLD_VS_DVBT 54 -#define EM2882_BOARD_TERRATEC_HYBRID_XS 55 -#define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 -#define EM2883_BOARD_KWORLD_HYBRID_A316 57 -#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 - -/* Limits minimum and default number of buffers */ -#define EM28XX_MIN_BUF 4 -#define EM28XX_DEF_BUF 8 - -/* Params for validated field */ -#define EM28XX_BOARD_NOT_VALIDATED 1 -#define EM28XX_BOARD_VALIDATED 0 - -/* maximum number of em28xx boards */ -#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */ - -/* maximum number of frames that can be queued */ -#define EM28XX_NUM_FRAMES 5 -/* number of frames that get used for v4l2_read() */ -#define EM28XX_NUM_READ_FRAMES 2 - -/* number of buffers for isoc transfers */ -#define EM28XX_NUM_BUFS 5 - -/* number of packets for each buffer - windows requests only 40 packets .. so we better do the same - this is what I found out for all alternate numbers there! - */ -#define EM28XX_NUM_PACKETS 40 - -/* default alternate; 0 means choose the best */ -#define EM28XX_PINOUT 0 - -#define EM28XX_INTERLACED_DEFAULT 1 - -/* -#define (use usbview if you want to get the other alternate number infos) -#define -#define alternate number 2 -#define Endpoint Address: 82 - Direction: in - Attribute: 1 - Type: Isoc - Max Packet Size: 1448 - Interval: 125us - - alternate number 7 - - Endpoint Address: 82 - Direction: in - Attribute: 1 - Type: Isoc - Max Packet Size: 3072 - Interval: 125us -*/ - -/* time to wait when stopping the isoc transfer */ -#define EM28XX_URB_TIMEOUT msecs_to_jiffies(EM28XX_NUM_BUFS * EM28XX_NUM_PACKETS) - -/* time in msecs to wait for i2c writes to finish */ -#define EM2800_I2C_WRITE_TIMEOUT 20 - -enum em28xx_mode { - EM28XX_MODE_UNDEFINED, - EM28XX_ANALOG_MODE, - EM28XX_DIGITAL_MODE, -}; - -enum em28xx_stream_state { - STREAM_OFF, - STREAM_INTERRUPT, - STREAM_ON, -}; - -struct em28xx; - -struct em28xx_usb_isoc_ctl { - /* max packet size of isoc transaction */ - int max_pkt_size; - - /* number of allocated urbs */ - int num_bufs; - - /* urb for isoc transfers */ - struct urb **urb; - - /* transfer buffers for isoc transfer */ - char **transfer_buffer; - - /* Last buffer command and region */ - u8 cmd; - int pos, size, pktsize; - - /* Last field: ODD or EVEN? */ - int field; - - /* Stores incomplete commands */ - u32 tmp_buf; - int tmp_buf_len; - - /* Stores already requested buffers */ - struct em28xx_buffer *buf; - - /* Stores the number of received fields */ - int nfields; - - /* isoc urb callback */ - int (*isoc_copy) (struct em28xx *dev, struct urb *urb); - -}; - -struct em28xx_fmt { - char *name; - u32 fourcc; /* v4l2 format id */ -}; - -/* buffer for one video frame */ -struct em28xx_buffer { - /* common v4l buffer stuff -- must be first */ - struct videobuf_buffer vb; - - struct list_head frame; - int top_field; - int receiving; -}; - -struct em28xx_dmaqueue { - struct list_head active; - struct list_head queued; - - wait_queue_head_t wq; - - /* Counters to control buffer fill */ - int pos; -}; - -/* io methods */ -enum em28xx_io_method { - IO_NONE, - IO_READ, - IO_MMAP, -}; - -/* inputs */ - -#define MAX_EM28XX_INPUT 4 -enum enum28xx_itype { - EM28XX_VMUX_COMPOSITE1 = 1, - EM28XX_VMUX_COMPOSITE2, - EM28XX_VMUX_COMPOSITE3, - EM28XX_VMUX_COMPOSITE4, - EM28XX_VMUX_SVIDEO, - EM28XX_VMUX_TELEVISION, - EM28XX_VMUX_CABLE, - EM28XX_VMUX_DVB, - EM28XX_VMUX_DEBUG, - EM28XX_RADIO, -}; - -enum em28xx_amux { - EM28XX_AMUX_VIDEO, - EM28XX_AMUX_LINE_IN, - EM28XX_AMUX_AC97_VIDEO, - EM28XX_AMUX_AC97_LINE_IN, -}; - -struct em28xx_input { - enum enum28xx_itype type; - unsigned int vmux; - enum em28xx_amux amux; -}; - -#define INPUT(nr) (&em28xx_boards[dev->model].input[nr]) - -enum em28xx_decoder { - EM28XX_TVP5150, - EM28XX_SAA7113, - EM28XX_SAA7114 -}; - -struct em28xx_reg_seq { - int reg; - unsigned char val, mask; - int sleep; -}; - -struct em28xx_board { - char *name; - int vchannels; - int tuner_type; - - /* i2c flags */ - unsigned int tda9887_conf; - - unsigned int is_em2800:1; - unsigned int has_msp34xx:1; - unsigned int mts_firmware:1; - unsigned int has_12mhz_i2s:1; - unsigned int max_range_640_480:1; - unsigned int has_dvb:1; - unsigned int has_snapshot_button:1; - unsigned int valid:1; - - enum em28xx_decoder decoder; - - struct em28xx_input input[MAX_EM28XX_INPUT]; - struct em28xx_input radio; -}; - -struct em28xx_eeprom { - u32 id; /* 0x9567eb1a */ - u16 vendor_ID; - u16 product_ID; - - u16 chip_conf; - - u16 board_conf; - - u16 string1, string2, string3; - - u8 string_idx_table; -}; - -/* device states */ -enum em28xx_dev_state { - DEV_INITIALIZED = 0x01, - DEV_DISCONNECTED = 0x02, - DEV_MISCONFIGURED = 0x04, -}; - -#define EM28XX_AUDIO_BUFS 5 -#define EM28XX_NUM_AUDIO_PACKETS 64 -#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */ -#define EM28XX_CAPTURE_STREAM_EN 1 - -/* em28xx extensions */ -#define EM28XX_AUDIO 0x10 -#define EM28XX_DVB 0x20 - -struct em28xx_audio { - char name[50]; - char *transfer_buffer[EM28XX_AUDIO_BUFS]; - struct urb *urb[EM28XX_AUDIO_BUFS]; - struct usb_device *udev; - unsigned int capture_transfer_done; - struct snd_pcm_substream *capture_pcm_substream; - - unsigned int hwptr_done_capture; - struct snd_card *sndcard; - - int users, shutdown; - enum em28xx_stream_state capture_stream; - spinlock_t slock; -}; - -struct em28xx; - -struct em28xx_fh { - struct em28xx *dev; - unsigned int stream_on:1; /* Locks streams */ - int radio; - - struct videobuf_queue vb_vidq; - - enum v4l2_buf_type type; -}; - -/* main device struct */ -struct em28xx { - /* generic device properties */ - char name[30]; /* name (including minor) of the device */ - int model; /* index in the device_data struct */ - int devno; /* marks the number of this device */ - unsigned int is_em2800:1; - unsigned int has_msp34xx:1; - unsigned int has_tda9887:1; - unsigned int stream_on:1; /* Locks streams */ - unsigned int has_audio_class:1; - unsigned int has_12mhz_i2s:1; - unsigned int max_range_640_480:1; - unsigned int has_dvb:1; - unsigned int has_snapshot_button:1; - unsigned int valid:1; /* report for validated boards */ - - /* Some older em28xx chips needs a waiting time after writing */ - unsigned int wait_after_write; - - /* GPIO sequences for analog and digital mode */ - struct em28xx_reg_seq *analog_gpio, *digital_gpio; - - /* GPIO sequences for tuner callbacks */ - struct em28xx_reg_seq *tun_analog_gpio, *tun_digital_gpio; - - int video_inputs; /* number of video inputs */ - struct list_head devlist; - - u32 i2s_speed; /* I2S speed for audio digital stream */ - - enum em28xx_decoder decoder; - - int tuner_type; /* type of the tuner */ - int tuner_addr; /* tuner address */ - int tda9887_conf; - /* i2c i/o */ - struct i2c_adapter i2c_adap; - struct i2c_client i2c_client; - /* video for linux */ - int users; /* user count for exclusive use */ - struct video_device *vdev; /* video for linux device struct */ - v4l2_std_id norm; /* selected tv norm */ - int ctl_freq; /* selected frequency */ - unsigned int ctl_input; /* selected input */ - unsigned int ctl_ainput;/* selected audio input */ - int mute; - int volume; - /* frame properties */ - int width; /* current frame width */ - int height; /* current frame height */ - int hscale; /* horizontal scale factor (see datasheet) */ - int vscale; /* vertical scale factor (see datasheet) */ - int interlaced; /* 1=interlace fileds, 0=just top fileds */ - unsigned int video_bytesread; /* Number of bytes read */ - - unsigned long hash; /* eeprom hash - for boards with generic ID */ - unsigned long i2c_hash; /* i2c devicelist hash - - for boards with generic ID */ - - struct em28xx_audio *adev; - - /* states */ - enum em28xx_dev_state state; - enum em28xx_io_method io; - - struct work_struct request_module_wk; - - /* locks */ - struct mutex lock; - /* spinlock_t queue_lock; */ - struct list_head inqueue, outqueue; - wait_queue_head_t open, wait_frame, wait_stream; - struct video_device *vbi_dev; - struct video_device *radio_dev; - - unsigned char eedata[256]; - - /* Isoc control struct */ - struct em28xx_dmaqueue vidq; - struct em28xx_usb_isoc_ctl isoc_ctl; - spinlock_t slock; - - /* usb transfer */ - struct usb_device *udev; /* the usb device */ - int alt; /* alternate */ - int max_pkt_size; /* max packet size of isoc transaction */ - int num_alt; /* Number of alternative settings */ - unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */ - struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */ - char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */ - /* helper funcs that call usb_control_msg */ - int (*em28xx_write_regs) (struct em28xx *dev, u16 reg, - char *buf, int len); - int (*em28xx_read_reg) (struct em28xx *dev, u16 reg); - int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg, - char *buf, int len); - int (*em28xx_write_regs_req) (struct em28xx *dev, u8 req, u16 reg, - char *buf, int len); - int (*em28xx_read_reg_req) (struct em28xx *dev, u8 req, u16 reg); - - enum em28xx_mode mode; - - /* Caches GPO and GPIO registers */ - unsigned char reg_gpo, reg_gpio; - - /* Snapshot button */ - char snapshot_button_path[30]; /* path of the input dev */ - struct input_dev *sbutton_input_dev; - struct delayed_work sbutton_query_work; - - struct em28xx_dvb *dvb; -}; - -struct em28xx_ops { - struct list_head next; - char *name; - int id; - int (*init)(struct em28xx *); - int (*fini)(struct em28xx *); -}; - -/* Provided by em28xx-i2c.c */ - -void em28xx_i2c_call_clients(struct em28xx *dev, unsigned int cmd, void *arg); -void em28xx_do_i2c_scan(struct em28xx *dev); -int em28xx_i2c_register(struct em28xx *dev); -int em28xx_i2c_unregister(struct em28xx *dev); - -/* Provided by em28xx-core.c */ - -u32 em28xx_request_buffers(struct em28xx *dev, u32 count); -void em28xx_queue_unusedframes(struct em28xx *dev); -void em28xx_release_buffers(struct em28xx *dev); - -int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, - char *buf, int len); -int em28xx_read_reg_req(struct em28xx *dev, u8 req, u16 reg); -int em28xx_read_reg(struct em28xx *dev, u16 reg); -int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, - int len); -int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len); -int em28xx_audio_analog_set(struct em28xx *dev); - -int em28xx_colorlevels_set_default(struct em28xx *dev); -int em28xx_capture_start(struct em28xx *dev, int start); -int em28xx_outfmt_set_yuv422(struct em28xx *dev); -int em28xx_resolution_set(struct em28xx *dev); -int em28xx_set_alternate(struct em28xx *dev); -int em28xx_init_isoc(struct em28xx *dev, int max_packets, - int num_bufs, int max_pkt_size, - int (*isoc_copy) (struct em28xx *dev, struct urb *urb)); -void em28xx_uninit_isoc(struct em28xx *dev); -int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode); -int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio); - -/* Provided by em28xx-video.c */ -int em28xx_register_extension(struct em28xx_ops *dev); -void em28xx_unregister_extension(struct em28xx_ops *dev); - -/* Provided by em28xx-cards.c */ -extern int em2800_variant_detect(struct usb_device *udev, int model); -extern void em28xx_pre_card_setup(struct em28xx *dev); -extern void em28xx_card_setup(struct em28xx *dev); -extern struct em28xx_board em28xx_boards[]; -extern struct usb_device_id em28xx_id_table[]; -extern const unsigned int em28xx_bcount; -void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir); -int em28xx_tuner_callback(void *ptr, int command, int arg); - -/* Provided by em28xx-input.c */ -/* TODO: Check if the standard get_key handlers on ir-common can be used */ -int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); -int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw); -int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key, - u32 *ir_raw); -void em28xx_register_snapshot_button(struct em28xx *dev); -void em28xx_deregister_snapshot_button(struct em28xx *dev); - -/* printk macros */ - -#define em28xx_err(fmt, arg...) do {\ - printk(KERN_ERR fmt , ##arg); } while (0) - -#define em28xx_errdev(fmt, arg...) do {\ - printk(KERN_ERR "%s: "fmt,\ - dev->name , ##arg); } while (0) - -#define em28xx_info(fmt, arg...) do {\ - printk(KERN_INFO "%s: "fmt,\ - dev->name , ##arg); } while (0) -#define em28xx_warn(fmt, arg...) do {\ - printk(KERN_WARNING "%s: "fmt,\ - dev->name , ##arg); } while (0) - -static inline int em28xx_compression_disable(struct em28xx *dev) -{ - /* side effect of disabling scaler and mixer */ - return em28xx_write_regs(dev, EM28XX_R26_COMPR, "\x00", 1); -} - -static inline int em28xx_contrast_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f; -} - -static inline int em28xx_brightness_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R21_YOFFSET); -} - -static inline int em28xx_saturation_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f; -} - -static inline int em28xx_u_balance_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R23_UOFFSET); -} - -static inline int em28xx_v_balance_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R24_VOFFSET); -} - -static inline int em28xx_gamma_get(struct em28xx *dev) -{ - return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f; -} - -static inline int em28xx_contrast_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1); -} - -static inline int em28xx_brightness_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1); -} - -static inline int em28xx_saturation_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1); -} - -static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1); -} - -static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1); -} - -static inline int em28xx_gamma_set(struct em28xx *dev, s32 val) -{ - u8 tmp = (u8) val; - return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1); -} - -/*FIXME: maxw should be dependent of alt mode */ -static inline unsigned int norm_maxw(struct em28xx *dev) -{ - if (dev->max_range_640_480) - return 640; - else - return 720; -} - -static inline unsigned int norm_maxh(struct em28xx *dev) -{ - if (dev->max_range_640_480) - return 480; - else - return (dev->norm & V4L2_STD_625_50) ? 576 : 480; -} -#endif |
