diff options
Diffstat (limited to 'drivers/media/video')
83 files changed, 10684 insertions, 3713 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index d82c8a30ba4..c622a4da566 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -26,6 +26,7 @@ config VIDEO_BT848 select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM + select VIDEO_MSP3400 ---help--- Support for BT848 based frame grabber/overlay boards. This includes the Miro, Hauppauge and STB boards. Please read the material in @@ -142,6 +143,8 @@ config VIDEO_CPIA_USB otherwise say N. This will not work with the Creative Webcam III. It is also available as a module (cpia_usb). +source "drivers/media/video/cpia2/Kconfig" + config VIDEO_SAA5246A tristate "SAA5246A, SAA5281 Teletext processor" depends on VIDEO_DEV && I2C @@ -339,18 +342,53 @@ config VIDEO_M32R_AR_M64278 Say Y here to use the Renesas M64278E-800 camera module, which supports VGA(640x480 pixcels) size of images. -config VIDEO_AUDIO_DECODER - tristate "Add support for additional audio chipsets" +config VIDEO_MSP3400 + tristate "Micronas MSP34xx audio decoders" + depends on VIDEO_DEV && I2C + ---help--- + Support for the Micronas MSP34xx series of audio decoders. + + To compile this driver as a module, choose M here: the + module will be called msp3400 + +config VIDEO_CS53L32A + tristate "Cirrus Logic CS53L32A audio ADC" depends on VIDEO_DEV && I2C && EXPERIMENTAL ---help--- - Say Y here to compile drivers for WM8775 and CS53L32A audio - decoders. + Support for the Cirrus Logic CS53L32A low voltage + stereo A/D converter. -config VIDEO_DECODER - tristate "Add support for additional video chipsets" + To compile this driver as a module, choose M here: the + module will be called cs53l32a + +config VIDEO_WM8775 + tristate "Wolfson Microelectronics WM8775 audio ADC" depends on VIDEO_DEV && I2C && EXPERIMENTAL ---help--- - Say Y here to compile drivers for SAA7115, SAA7127 and CX25840 - video decoders. + Support for the Wolfson Microelectronics WM8775 + high performance stereo A/D Converter. + + To compile this driver as a module, choose M here: the + module will be called wm8775 + +source "drivers/media/video/cx25840/Kconfig" + +config VIDEO_SAA711X + tristate "Philips SAA7113/4/5 video decoders" + depends on VIDEO_DEV && I2C && EXPERIMENTAL + ---help--- + Support for the Philips SAA7113/4/5 video decoders. + + To compile this driver as a module, choose M here: the + module will be called saa7115 + +config VIDEO_SAA7127 + tristate "Philips SAA7127/9 digital video encoders" + depends on VIDEO_DEV && I2C && EXPERIMENTAL + ---help--- + Support for the Philips SAA7127/9 digital video encoders. + + To compile this driver as a module, choose M here: the + module will be called saa7127 endmenu diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index faf728366c4..f2bd4c0c4f1 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile @@ -15,7 +15,7 @@ msp3400-objs := msp3400-driver.o msp3400-kthreads.o obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o -obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ +obj-$(CONFIG_VIDEO_BT848) += bttv.o tvaudio.o \ tda7432.o tda9875.o ir-kbd-i2c.o obj-$(CONFIG_SOUND_TVMIXER) += tvmixer.o @@ -44,10 +44,13 @@ obj-$(CONFIG_VIDEO_MEYE) += meye.o obj-$(CONFIG_VIDEO_SAA7134) += ir-kbd-i2c.o saa7134/ obj-$(CONFIG_VIDEO_CX88) += cx88/ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ -obj-$(CONFIG_VIDEO_EM28XX) += saa711x.o tvp5150.o -obj-$(CONFIG_VIDEO_AUDIO_DECODER) += wm8775.o cs53l32a.o +obj-$(CONFIG_VIDEO_EM28XX) += tvp5150.o +obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o +obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o +obj-$(CONFIG_VIDEO_WM8775) += wm8775.o obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/ -obj-$(CONFIG_VIDEO_MXB) += saa7111.o tuner.o tda9840.o tea6415c.o tea6420.o mxb.o +obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ +obj-$(CONFIG_VIDEO_MXB) += saa7111.o tda9840.o tea6415c.o tea6420.o mxb.o obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o obj-$(CONFIG_VIDEO_DPC) += saa7111.o dpc7146.o @@ -61,6 +64,8 @@ obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o -obj-$(CONFIG_VIDEO_DECODER) += saa7115.o cx25840/ saa7127.o +obj-$(CONFIG_VIDEO_CX25840) += cx25840/ +obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o +obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o EXTRA_CFLAGS += -I$(srctree)/drivers/media/dvb/dvb-core diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c index 994b75fe165..c586f64b6b7 100644 --- a/drivers/media/video/arv.c +++ b/drivers/media/video/arv.c @@ -31,8 +31,8 @@ #include <linux/mm.h> #include <linux/sched.h> #include <linux/videodev.h> +#include <linux/mutex.h> -#include <asm/semaphore.h> #include <asm/uaccess.h> #include <asm/m32r.h> #include <asm/io.h> @@ -117,7 +117,7 @@ struct ar_device { int width, height; int frame_bytes, line_bytes; wait_queue_head_t wait; - struct semaphore lock; + struct mutex lock; }; static int video_nr = -1; /* video device number (first free) */ @@ -288,7 +288,7 @@ static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos) if (ar->mode == AR_MODE_NORMAL) arvcr1 |= ARVCR1_NORMAL; - down(&ar->lock); + mutex_lock(&ar->lock); #if USE_INT local_irq_save(flags); @@ -392,7 +392,7 @@ static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos) } DEBUG(1, "ret = %d\n", ret); out_up: - up(&ar->lock); + mutex_unlock(&ar->lock); return ret; } @@ -456,7 +456,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file, (w->width != AR_WIDTH_QVGA || w->height != AR_HEIGHT_QVGA)) return -EINVAL; - down(&ar->lock); + mutex_lock(&ar->lock); ar->width = w->width; ar->height = w->height; if (ar->width == AR_WIDTH_VGA) { @@ -473,7 +473,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file, ar->line_bytes = AR_LINE_BYTES_QVGA; ar->mode = AR_MODE_INTERLACE; } - up(&ar->lock); + mutex_unlock(&ar->lock); return 0; } case VIDIOCGFBUF: @@ -734,7 +734,7 @@ static int ar_initialize(struct video_device *dev) void ar_release(struct video_device *vfd) { struct ar_device *ar = vfd->priv; - down(&ar->lock); + mutex_lock(&ar->lock); video_device_release(vfd); } @@ -824,7 +824,7 @@ static int __init ar_init(void) ar->line_bytes = AR_LINE_BYTES_QVGA; ar->mode = AR_MODE_INTERLACE; } - init_MUTEX(&ar->lock); + mutex_init(&ar->lock); init_waitqueue_head(&ar->wait); #if USE_INT diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c index 9749d6ed623..abfa6ad857a 100644 --- a/drivers/media/video/bttv-cards.c +++ b/drivers/media/video/bttv-cards.c @@ -137,6 +137,8 @@ MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a li MODULE_PARM_DESC(pll,"specify installed crystal (0=none, 28=28 MHz, 35=35 MHz)"); MODULE_PARM_DESC(tuner,"specify installed tuner type"); MODULE_PARM_DESC(autoload,"automatically load i2c modules like tuner.o, default is 1 (yes)"); +MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" + " [some VIA/SIS chipsets are known to have problem with overlay]"); /* ----------------------------------------------------------------------- */ /* list of card IDs for bt878+ cards */ @@ -275,7 +277,6 @@ static struct CARD { { 0x03116000, BTTV_BOARD_SENSORAY311, "Sensoray 311" }, { 0x00790e11, BTTV_BOARD_WINDVR, "Canopus WinDVR PCI" }, { 0xa0fca1a0, BTTV_BOARD_ZOLTRIX, "Face to Face Tvmax" }, - { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"}, { 0x82b2aa6a, BTTV_BOARD_SIMUS_GVC1100, "SIMUS GVC1100" }, { 0x146caa0c, BTTV_BOARD_PV951, "ituner spectra8" }, { 0x200a1295, BTTV_BOARD_PXC200, "ImageNation PXC200A" }, @@ -297,13 +298,14 @@ static struct CARD { * { 0x13eb0070, BTTV_BOARD_HAUPPAUGE_IMPACTVCB, "Hauppauge ImpactVCB" }, */ /* DVB cards (using pci function .1 for mpeg data xfer) */ - { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, - { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, { 0x001c11bd, BTTV_BOARD_PINNACLESAT, "Pinnacle PCTV Sat" }, + { 0x01010071, BTTV_BOARD_NEBULA_DIGITV, "Nebula Electronics DigiTV" }, + { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"}, { 0x002611bd, BTTV_BOARD_TWINHAN_DST, "Pinnacle PCTV SAT CI" }, { 0x00011822, BTTV_BOARD_TWINHAN_DST, "Twinhan VisionPlus DVB" }, { 0xfc00270f, BTTV_BOARD_TWINHAN_DST, "ChainTech digitop DST-1000 DVB-S" }, { 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, + { 0x07611461, BTTV_BOARD_AVDVBT_761, "AverMedia AverTV DVB-T 761" }, { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" }, { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, @@ -4944,12 +4946,14 @@ void __devinit bttv_check_chipset(void) if (vsfx) printk(KERN_INFO "bttv: Host bridge needs VSFX enabled.\n"); if (pcipci_fail) { - printk(KERN_WARNING "bttv: BT848 and your chipset may not work together.\n"); + printk(KERN_INFO "bttv: bttv and your chipset may not work " + "together.\n"); if (!no_overlay) { - printk(KERN_WARNING "bttv: overlay will be disabled.\n"); + printk(KERN_INFO "bttv: overlay will be disabled.\n"); no_overlay = 1; } else { - printk(KERN_WARNING "bttv: overlay forced. Use this option at your own risk.\n"); + printk(KERN_INFO "bttv: overlay forced. Use this " + "option at your own risk.\n"); } } if (UNSET != latency) diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c index 578b2008508..c0415d6e7fe 100644 --- a/drivers/media/video/bttv-driver.c +++ b/drivers/media/video/bttv-driver.c @@ -1965,7 +1965,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv, BUG(); } - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); kfree(fh->ov.clips); fh->ov.clips = clips; fh->ov.nclips = n; @@ -1986,7 +1986,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv, bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new); retval = bttv_switch_overlay(btv,fh,new); } - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return retval; } @@ -2166,7 +2166,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); /* update our state informations */ - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); fh->fmt = fmt; fh->cap.field = f->fmt.pix.field; fh->cap.last = V4L2_FIELD_NONE; @@ -2175,7 +2175,7 @@ static int bttv_s_fmt(struct bttv_fh *fh, struct bttv *btv, btv->init.fmt = fmt; btv->init.width = f->fmt.pix.width; btv->init.height = f->fmt.pix.height; - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return 0; } @@ -2282,7 +2282,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, fmt = format_by_palette(pic->palette); if (NULL == fmt) return -EINVAL; - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); if (fmt->depth != pic->depth) { retval = -EINVAL; goto fh_unlock_and_return; @@ -2313,7 +2313,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, bt848_contrast(btv,pic->contrast); bt848_hue(btv,pic->hue); bt848_sat(btv,pic->colour); - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return 0; } @@ -2379,7 +2379,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, return -EPERM; end = (unsigned long)fbuf->base + fbuf->height * fbuf->bytesperline; - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); retval = -EINVAL; switch (fbuf->depth) { @@ -2417,7 +2417,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, btv->fbuf.fmt.bytesperline = fbuf->bytesperline; else btv->fbuf.fmt.bytesperline = btv->fbuf.fmt.width*fbuf->depth/8; - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return 0; } @@ -2440,7 +2440,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, if (!check_alloc_btres(btv,fh,RESOURCE_OVERLAY)) return -EBUSY; - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); if (*on) { fh->ov.tvnorm = btv->tvnorm; new = videobuf_alloc(sizeof(*new)); @@ -2451,7 +2451,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, /* switch over */ retval = bttv_switch_overlay(btv,fh,new); - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return retval; } @@ -2460,7 +2460,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, struct video_mbuf *mbuf = arg; unsigned int i; - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); retval = videobuf_mmap_setup(&fh->cap,gbuffers,gbufsize, V4L2_MEMORY_MMAP); if (retval < 0) @@ -2470,7 +2470,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, mbuf->size = gbuffers * gbufsize; for (i = 0; i < gbuffers; i++) mbuf->offsets[i] = i * gbufsize; - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return 0; } case VIDIOCMCAPTURE: @@ -2482,7 +2482,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, if (vm->frame >= VIDEO_MAX_FRAME) return -EINVAL; - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); retval = -EINVAL; buf = (struct bttv_buffer *)fh->cap.bufs[vm->frame]; if (NULL == buf) @@ -2504,7 +2504,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, spin_lock_irqsave(&btv->s_lock,flags); buffer_queue(&fh->cap,&buf->vb); spin_unlock_irqrestore(&btv->s_lock,flags); - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return 0; } case VIDIOCSYNC: @@ -2515,7 +2515,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, if (*frame >= VIDEO_MAX_FRAME) return -EINVAL; - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); retval = -EINVAL; buf = (struct bttv_buffer *)fh->cap.bufs[*frame]; if (NULL == buf) @@ -2535,7 +2535,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, retval = -EINVAL; break; } - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return retval; } @@ -2719,7 +2719,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, if (0 == (fmt->flags & FORMAT_FLAGS_PACKED)) return -EINVAL; - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); retval = -EINVAL; if (fb->flags & V4L2_FBUF_FLAG_OVERLAY) { if (fb->fmt.width > bttv_tvnorms[btv->tvnorm].swidth) @@ -2759,7 +2759,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, retval = bttv_switch_overlay(btv,fh,new); } } - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return retval; } @@ -2890,7 +2890,7 @@ static int bttv_do_ioctl(struct inode *inode, struct file *file, return 0; fh_unlock_and_return: - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return retval; } @@ -2957,16 +2957,16 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream); } else { /* read() capture */ - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); if (NULL == fh->cap.read_buf) { /* need to capture a new frame */ if (locked_btres(fh->btv,RESOURCE_VIDEO)) { - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return POLLERR; } fh->cap.read_buf = videobuf_alloc(fh->cap.msize); if (NULL == fh->cap.read_buf) { - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return POLLERR; } fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR; @@ -2974,13 +2974,13 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait) if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,field)) { kfree (fh->cap.read_buf); fh->cap.read_buf = NULL; - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return POLLERR; } fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); fh->cap.read_off = 0; } - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); buf = (struct bttv_buffer*)fh->cap.read_buf; } diff --git a/drivers/media/video/bttv-input.c b/drivers/media/video/bttv-input.c index 221b36e7f39..69efa0e5174 100644 --- a/drivers/media/video/bttv-input.c +++ b/drivers/media/video/bttv-input.c @@ -28,251 +28,6 @@ #include "bttv.h" #include "bttvp.h" -/* ---------------------------------------------------------------------- */ - -static IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE] = { - [ 34 ] = KEY_KP0, - [ 40 ] = KEY_KP1, - [ 24 ] = KEY_KP2, - [ 56 ] = KEY_KP3, - [ 36 ] = KEY_KP4, - [ 20 ] = KEY_KP5, - [ 52 ] = KEY_KP6, - [ 44 ] = KEY_KP7, - [ 28 ] = KEY_KP8, - [ 60 ] = KEY_KP9, - - [ 48 ] = KEY_EJECTCD, // Unmarked on my controller - [ 0 ] = KEY_POWER, - [ 18 ] = BTN_LEFT, // DISPLAY/L - [ 50 ] = BTN_RIGHT, // LOOP/R - [ 10 ] = KEY_MUTE, - [ 38 ] = KEY_RECORD, - [ 22 ] = KEY_PAUSE, - [ 54 ] = KEY_STOP, - [ 30 ] = KEY_VOLUMEDOWN, - [ 62 ] = KEY_VOLUMEUP, - - [ 32 ] = KEY_TUNER, // TV/FM - [ 16 ] = KEY_CD, - [ 8 ] = KEY_VIDEO, - [ 4 ] = KEY_AUDIO, - [ 12 ] = KEY_ZOOM, // full screen - [ 2 ] = KEY_INFO, // preview - [ 42 ] = KEY_SEARCH, // autoscan - [ 26 ] = KEY_STOP, // freeze - [ 58 ] = KEY_RECORD, // capture - [ 6 ] = KEY_PLAY, // unmarked - [ 46 ] = KEY_RED, // unmarked - [ 14 ] = KEY_GREEN, // unmarked - - [ 33 ] = KEY_YELLOW, // unmarked - [ 17 ] = KEY_CHANNELDOWN, - [ 49 ] = KEY_CHANNELUP, - [ 1 ] = KEY_BLUE, // unmarked -}; - -/* Matt Jesson <dvb@jesson.eclipse.co.uk */ -static IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = { - [ 0x28 ] = KEY_KP0, //'0' / 'enter' - [ 0x22 ] = KEY_KP1, //'1' - [ 0x12 ] = KEY_KP2, //'2' / 'up arrow' - [ 0x32 ] = KEY_KP3, //'3' - [ 0x24 ] = KEY_KP4, //'4' / 'left arrow' - [ 0x14 ] = KEY_KP5, //'5' - [ 0x34 ] = KEY_KP6, //'6' / 'right arrow' - [ 0x26 ] = KEY_KP7, //'7' - [ 0x16 ] = KEY_KP8, //'8' / 'down arrow' - [ 0x36 ] = KEY_KP9, //'9' - - [ 0x20 ] = KEY_LIST, // 'source' - [ 0x10 ] = KEY_TEXT, // 'teletext' - [ 0x00 ] = KEY_POWER, // 'power' - [ 0x04 ] = KEY_AUDIO, // 'audio' - [ 0x06 ] = KEY_ZOOM, // 'full screen' - [ 0x18 ] = KEY_VIDEO, // 'display' - [ 0x38 ] = KEY_SEARCH, // 'loop' - [ 0x08 ] = KEY_INFO, // 'preview' - [ 0x2a ] = KEY_REWIND, // 'backward <<' - [ 0x1a ] = KEY_FASTFORWARD, // 'forward >>' - [ 0x3a ] = KEY_RECORD, // 'capture' - [ 0x0a ] = KEY_MUTE, // 'mute' - [ 0x2c ] = KEY_RECORD, // 'record' - [ 0x1c ] = KEY_PAUSE, // 'pause' - [ 0x3c ] = KEY_STOP, // 'stop' - [ 0x0c ] = KEY_PLAY, // 'play' - [ 0x2e ] = KEY_RED, // 'red' - [ 0x01 ] = KEY_BLUE, // 'blue' / 'cancel' - [ 0x0e ] = KEY_YELLOW, // 'yellow' / 'ok' - [ 0x21 ] = KEY_GREEN, // 'green' - [ 0x11 ] = KEY_CHANNELDOWN, // 'channel -' - [ 0x31 ] = KEY_CHANNELUP, // 'channel +' - [ 0x1e ] = KEY_VOLUMEDOWN, // 'volume -' - [ 0x3e ] = KEY_VOLUMEUP, // 'volume +' -}; - -/* Attila Kondoros <attila.kondoros@chello.hu> */ -static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = { - - [ 1 ] = KEY_KP1, - [ 2 ] = KEY_KP2, - [ 3 ] = KEY_KP3, - [ 4 ] = KEY_KP4, - [ 5 ] = KEY_KP5, - [ 6 ] = KEY_KP6, - [ 7 ] = KEY_KP7, - [ 8 ] = KEY_KP8, - [ 9 ] = KEY_KP9, - [ 0 ] = KEY_KP0, - [ 23 ] = KEY_LAST, // +100 - [ 10 ] = KEY_LIST, // recall - - - [ 28 ] = KEY_TUNER, // TV/FM - [ 21 ] = KEY_SEARCH, // scan - [ 18 ] = KEY_POWER, // power - [ 31 ] = KEY_VOLUMEDOWN, // vol up - [ 27 ] = KEY_VOLUMEUP, // vol down - [ 30 ] = KEY_CHANNELDOWN, // chn up - [ 26 ] = KEY_CHANNELUP, // chn down - - [ 17 ] = KEY_VIDEO, // video - [ 15 ] = KEY_ZOOM, // full screen - [ 19 ] = KEY_MUTE, // mute/unmute - [ 16 ] = KEY_TEXT, // min - - [ 13 ] = KEY_STOP, // freeze - [ 14 ] = KEY_RECORD, // record - [ 29 ] = KEY_PLAYPAUSE, // stop - [ 25 ] = KEY_PLAY, // play - - [ 22 ] = KEY_GOTO, // osd - [ 20 ] = KEY_REFRESH, // default - [ 12 ] = KEY_KPPLUS, // fine tune >>>> - [ 24 ] = KEY_KPMINUS // fine tune <<<< -}; - -/* ---------------------------------------------------------------------- */ - -static IR_KEYTAB_TYPE ir_codes_conceptronic[IR_KEYTAB_SIZE] = { - - [ 30 ] = KEY_POWER, // power - [ 7 ] = KEY_MEDIA, // source - [ 28 ] = KEY_SEARCH, // scan - -/* FIXME: duplicate keycodes? - * - * These four keys seem to share the same GPIO as CH+, CH-, <<< and >>> - * The GPIO values are - * 6397fb for both "Scan <" and "CH -", - * 639ffb for "Scan >" and "CH+", - * 6384fb for "Tune <" and "<<<", - * 638cfb for "Tune >" and ">>>", regardless of the mask. - * - * [ 23 ] = KEY_BACK, // fm scan << - * [ 31 ] = KEY_FORWARD, // fm scan >> - * - * [ 4 ] = KEY_LEFT, // fm tuning < - * [ 12 ] = KEY_RIGHT, // fm tuning > - * - * For now, these four keys are disabled. Pressing them will generate - * the CH+/CH-/<<</>>> events - */ - - [ 3 ] = KEY_TUNER, // TV/FM - - [ 0 ] = KEY_RECORD, - [ 8 ] = KEY_STOP, - [ 17 ] = KEY_PLAY, - - [ 26 ] = KEY_PLAYPAUSE, // freeze - [ 25 ] = KEY_ZOOM, // zoom - [ 15 ] = KEY_TEXT, // min - - [ 1 ] = KEY_KP1, - [ 11 ] = KEY_KP2, - [ 27 ] = KEY_KP3, - [ 5 ] = KEY_KP4, - [ 9 ] = KEY_KP5, - [ 21 ] = KEY_KP6, - [ 6 ] = KEY_KP7, - [ 10 ] = KEY_KP8, - [ 18 ] = KEY_KP9, - [ 2 ] = KEY_KP0, - [ 16 ] = KEY_LAST, // +100 - [ 19 ] = KEY_LIST, // recall - - [ 31 ] = KEY_CHANNELUP, // chn down - [ 23 ] = KEY_CHANNELDOWN, // chn up - [ 22 ] = KEY_VOLUMEUP, // vol down - [ 20 ] = KEY_VOLUMEDOWN, // vol up - - [ 4 ] = KEY_KPMINUS, // <<< - [ 14 ] = KEY_SETUP, // function - [ 12 ] = KEY_KPPLUS, // >>> - - [ 13 ] = KEY_GOTO, // mts - [ 29 ] = KEY_REFRESH, // reset - [ 24 ] = KEY_MUTE // mute/unmute -}; - -static IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = { - [0x00] = KEY_KP0, - [0x01] = KEY_KP1, - [0x02] = KEY_KP2, - [0x03] = KEY_KP3, - [0x04] = KEY_KP4, - [0x05] = KEY_KP5, - [0x06] = KEY_KP6, - [0x07] = KEY_KP7, - [0x08] = KEY_KP8, - [0x09] = KEY_KP9, - [0x0a] = KEY_TV, - [0x0b] = KEY_AUX, - [0x0c] = KEY_DVD, - [0x0d] = KEY_POWER, - [0x0e] = KEY_MHP, /* labelled 'Picture' */ - [0x0f] = KEY_AUDIO, - [0x10] = KEY_INFO, - [0x11] = KEY_F13, /* 16:9 */ - [0x12] = KEY_F14, /* 14:9 */ - [0x13] = KEY_EPG, - [0x14] = KEY_EXIT, - [0x15] = KEY_MENU, - [0x16] = KEY_UP, - [0x17] = KEY_DOWN, - [0x18] = KEY_LEFT, - [0x19] = KEY_RIGHT, - [0x1a] = KEY_ENTER, - [0x1b] = KEY_CHANNELUP, - [0x1c] = KEY_CHANNELDOWN, - [0x1d] = KEY_VOLUMEUP, - [0x1e] = KEY_VOLUMEDOWN, - [0x1f] = KEY_RED, - [0x20] = KEY_GREEN, - [0x21] = KEY_YELLOW, - [0x22] = KEY_BLUE, - [0x23] = KEY_SUBTITLE, - [0x24] = KEY_F15, /* AD */ - [0x25] = KEY_TEXT, - [0x26] = KEY_MUTE, - [0x27] = KEY_REWIND, - [0x28] = KEY_STOP, - [0x29] = KEY_PLAY, - [0x2a] = KEY_FASTFORWARD, - [0x2b] = KEY_F16, /* chapter */ - [0x2c] = KEY_PAUSE, - [0x2d] = KEY_PLAY, - [0x2e] = KEY_RECORD, - [0x2f] = KEY_F17, /* picture in picture */ - [0x30] = KEY_KPPLUS, /* zoom in */ - [0x31] = KEY_KPMINUS, /* zoom out */ - [0x32] = KEY_F18, /* capture */ - [0x33] = KEY_F19, /* web */ - [0x34] = KEY_EMAIL, - [0x35] = KEY_PHONE, - [0x36] = KEY_PC -}; static int debug; module_param(debug, int, 0644); /* debug level (0,1,2) */ @@ -573,7 +328,8 @@ int bttv_input_init(struct bttv *btv) ir->polling = 50; // ms break; case BTTV_BOARD_CONCEPTRONIC_CTVFMI2: - ir_codes = ir_codes_conceptronic; + case BTTV_BOARD_CONTVFMI: + ir_codes = ir_codes_pixelview; ir->mask_keycode = 0x001F00; ir->mask_keyup = 0x006000; ir->polling = 50; // ms diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c index b40e9734bf0..344f84e9af0 100644 --- a/drivers/media/video/bttv-risc.c +++ b/drivers/media/video/bttv-risc.c @@ -51,8 +51,10 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, int rc; /* estimate risc mem: worst case is one write per page border + - one write per scan line + sync + jump (all 2 dwords) */ - instructions = (bpl * lines) / PAGE_SIZE + lines; + one write per scan line + sync + jump (all 2 dwords). padding + can cause next bpl to start close to a page border. First DMA + region may be smaller than PAGE_SIZE */ + instructions = 1 + ((bpl + padding) * lines) / PAGE_SIZE + lines; instructions += 2; if ((rc = btcx_riscmem_alloc(btv->c.pci,risc,instructions*8)) < 0) return rc; @@ -104,7 +106,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc, /* save pointer to jmp instruction address */ risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size); + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); return 0; } @@ -222,7 +224,7 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc, /* save pointer to jmp instruction address */ risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size); + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); return 0; } @@ -274,6 +276,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, if (line > maxy) btcx_calc_skips(line, ov->w.width, &maxy, skips, &nskips, ov->clips, ov->nclips); + else + nskips = 0; /* write out risc code */ for (start = 0, skip = 0; start < ov->w.width; start = end) { @@ -307,7 +311,7 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, /* save pointer to jmp instruction address */ risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size); + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); kfree(skips); return 0; } @@ -507,8 +511,7 @@ bttv_risc_hook(struct bttv *btv, int slot, struct btcx_riscmem *risc, void bttv_dma_free(struct bttv *btv, struct bttv_buffer *buf) { - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); videobuf_dma_pci_unmap(btv->c.pci, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c index 6bad93ef969..d97b7d8ac33 100644 --- a/drivers/media/video/bw-qcam.c +++ b/drivers/media/video/bw-qcam.c @@ -73,7 +73,7 @@ OTHER DEALINGS IN THE SOFTWARE. #include <linux/parport.h> #include <linux/sched.h> #include <linux/videodev.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #include "bw-qcam.h" @@ -168,7 +168,7 @@ static struct qcam_device *qcam_init(struct parport *port) memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); - init_MUTEX(&q->lock); + mutex_init(&q->lock); q->port_mode = (QC_ANY | QC_NOTSET); q->width = 320; @@ -772,9 +772,9 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file, qcam->whitebal = p->whiteness>>8; qcam->bpp = p->depth; - down(&qcam->lock); + mutex_lock(&qcam->lock); qc_setscanmode(qcam); - up(&qcam->lock); + mutex_unlock(&qcam->lock); qcam->status |= QC_PARAM_CHANGE; return 0; @@ -805,9 +805,9 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file, qcam->height = 240; qcam->transfer_scale = 1; } - down(&qcam->lock); + mutex_lock(&qcam->lock); qc_setscanmode(qcam); - up(&qcam->lock); + mutex_unlock(&qcam->lock); /* We must update the camera before we grab. We could just have changed the grab size */ @@ -854,7 +854,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf, int len; parport_claim_or_block(qcam->pdev); - down(&qcam->lock); + mutex_lock(&qcam->lock); qc_reset(qcam); @@ -864,7 +864,7 @@ static ssize_t qcam_read(struct file *file, char __user *buf, len=qc_capture(qcam, buf,count); - up(&qcam->lock); + mutex_unlock(&qcam->lock); parport_release(qcam->pdev); return len; diff --git a/drivers/media/video/bw-qcam.h b/drivers/media/video/bw-qcam.h index 723e8ad9e56..6701dafbc0d 100644 --- a/drivers/media/video/bw-qcam.h +++ b/drivers/media/video/bw-qcam.h @@ -55,7 +55,7 @@ struct qcam_device { struct video_device vdev; struct pardevice *pdev; struct parport *pport; - struct semaphore lock; + struct mutex lock; int width, height; int bpp; int mode; diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c index 9976db4f6da..8211fd8d7cb 100644 --- a/drivers/media/video/c-qcam.c +++ b/drivers/media/video/c-qcam.c @@ -34,7 +34,8 @@ #include <linux/parport.h> #include <linux/sched.h> #include <linux/videodev.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> + #include <asm/uaccess.h> struct qcam_device { @@ -47,7 +48,7 @@ struct qcam_device { int contrast, brightness, whitebal; int top, left; unsigned int bidirectional; - struct semaphore lock; + struct mutex lock; }; /* cameras maximum */ @@ -581,11 +582,11 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file, qcam->contrast = p->contrast>>8; qcam->whitebal = p->whiteness>>8; - down(&qcam->lock); + mutex_lock(&qcam->lock); parport_claim_or_block(qcam->pdev); qc_setup(qcam); parport_release(qcam->pdev); - up(&qcam->lock); + mutex_unlock(&qcam->lock); return 0; } case VIDIOCSWIN: @@ -628,11 +629,11 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file, #endif /* Ok we figured out what to use from our wide choice */ - down(&qcam->lock); + mutex_lock(&qcam->lock); parport_claim_or_block(qcam->pdev); qc_setup(qcam); parport_release(qcam->pdev); - up(&qcam->lock); + mutex_unlock(&qcam->lock); return 0; } case VIDIOCGWIN: @@ -672,12 +673,12 @@ static ssize_t qcam_read(struct file *file, char __user *buf, struct qcam_device *qcam=(struct qcam_device *)v; int len; - down(&qcam->lock); + mutex_lock(&qcam->lock); parport_claim_or_block(qcam->pdev); /* Probably should have a semaphore against multiple users */ len = qc_capture(qcam, buf,count); parport_release(qcam->pdev); - up(&qcam->lock); + mutex_unlock(&qcam->lock); return len; } @@ -727,7 +728,7 @@ static struct qcam_device *qcam_init(struct parport *port) memcpy(&q->vdev, &qcam_template, sizeof(qcam_template)); - init_MUTEX(&q->lock); + mutex_init(&q->lock); q->width = q->ccd_width = 320; q->height = q->ccd_height = 240; q->mode = QC_MILLIONS | QC_DECIMATION_1; diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c index 85d964b5b33..d93a561e6b8 100644 --- a/drivers/media/video/cpia.c +++ b/drivers/media/video/cpia.c @@ -39,7 +39,7 @@ #include <linux/pagemap.h> #include <linux/delay.h> #include <asm/io.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #ifdef CONFIG_KMOD #include <linux/kmod.h> @@ -622,7 +622,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf, buffer = page; - if (down_interruptible(&cam->param_lock)) + if (mutex_lock_interruptible(&cam->param_lock)) return -ERESTARTSYS; /* @@ -1350,7 +1350,7 @@ static int cpia_write_proc(struct file *file, const char __user *buf, } else DBG("error: %d\n", retval); - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); out: free_page((unsigned long)page); @@ -1664,7 +1664,7 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d) case CPIA_COMMAND_GetColourParams: case CPIA_COMMAND_GetColourBalance: case CPIA_COMMAND_GetExposure: - down(&cam->param_lock); + mutex_lock(&cam->param_lock); datasize=8; break; case CPIA_COMMAND_ReadMCPorts: @@ -1691,7 +1691,7 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d) if (command == CPIA_COMMAND_GetColourParams || command == CPIA_COMMAND_GetColourBalance || command == CPIA_COMMAND_GetExposure) - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); } else { switch(command) { case CPIA_COMMAND_GetCPIAVersion: @@ -1726,13 +1726,13 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d) cam->params.colourParams.brightness = data[0]; cam->params.colourParams.contrast = data[1]; cam->params.colourParams.saturation = data[2]; - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); break; case CPIA_COMMAND_GetColourBalance: cam->params.colourBalance.redGain = data[0]; cam->params.colourBalance.greenGain = data[1]; cam->params.colourBalance.blueGain = data[2]; - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); break; case CPIA_COMMAND_GetExposure: cam->params.exposure.gain = data[0]; @@ -1743,7 +1743,7 @@ static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d) cam->params.exposure.green1Comp = data[5]; cam->params.exposure.green2Comp = data[6]; cam->params.exposure.blueComp = data[7]; - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); break; case CPIA_COMMAND_ReadMCPorts: @@ -2059,7 +2059,7 @@ static int parse_picture(struct cam_data *cam, int size) int rows, cols, linesize, subsample_422; /* make sure params don't change while we are decoding */ - down(&cam->param_lock); + mutex_lock(&cam->param_lock); obuf = cam->decompressed_frame.data; end_obuf = obuf+CPIA_MAX_FRAME_SIZE; @@ -2069,26 +2069,26 @@ static int parse_picture(struct cam_data *cam, int size) if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) { LOG("header not found\n"); - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); return -1; } if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) { LOG("wrong video size\n"); - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); return -1; } if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) { LOG("illegal subtype %d\n",ibuf[17]); - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); return -1; } subsample_422 = ibuf[17] == SUBSAMPLE_422; if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) { LOG("illegal yuvorder %d\n",ibuf[18]); - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); return -1; } in_uyvy = ibuf[18] == YUVORDER_UYVY; @@ -2098,7 +2098,7 @@ static int parse_picture(struct cam_data *cam, int size) (ibuf[26] != cam->params.roi.rowStart) || (ibuf[27] != cam->params.roi.rowEnd)) { LOG("ROI mismatch\n"); - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); return -1; } cols = 8*(ibuf[25] - ibuf[24]); @@ -2107,14 +2107,14 @@ static int parse_picture(struct cam_data *cam, int size) if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) { LOG("illegal compression %d\n",ibuf[28]); - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); return -1; } compressed = (ibuf[28] == COMPRESSED); if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) { LOG("illegal decimation %d\n",ibuf[29]); - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); return -1; } decimation = (ibuf[29] == DECIMATION_ENAB); @@ -2130,7 +2130,7 @@ static int parse_picture(struct cam_data *cam, int size) cam->params.status.vpStatus = ibuf[38]; cam->params.status.errorCode = ibuf[39]; cam->fps = ibuf[41]; - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); linesize = skipcount(cols, out_fmt); ibuf += FRAME_HEADER_SIZE; @@ -2271,9 +2271,9 @@ static int find_over_exposure(int brightness) /* update various camera modes and settings */ static void dispatch_commands(struct cam_data *cam) { - down(&cam->param_lock); + mutex_lock(&cam->param_lock); if (cam->cmd_queue==COMMAND_NONE) { - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); return; } DEB_BYTE(cam->cmd_queue); @@ -2415,7 +2415,7 @@ static void dispatch_commands(struct cam_data *cam) } cam->cmd_queue = COMMAND_NONE; - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); return; } @@ -2562,7 +2562,7 @@ static void monitor_exposure(struct cam_data *cam) gain = data[2]; coarseL = data[3]; - down(&cam->param_lock); + mutex_lock(&cam->param_lock); light_exp = cam->params.colourParams.brightness + TC - 50 + EXP_ACC_LIGHT; if(light_exp > 255) @@ -2762,7 +2762,7 @@ static void monitor_exposure(struct cam_data *cam) LOG("Automatically increasing sensor_fps\n"); } } - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); } /*-----------------------------------------------------------------*/ @@ -2778,10 +2778,10 @@ static void restart_flicker(struct cam_data *cam) int cam_exposure, old_exp; if(!FIRMWARE_VERSION(1,2)) return; - down(&cam->param_lock); + mutex_lock(&cam->param_lock); if(cam->params.flickerControl.flickerMode == 0 || cam->raw_image[39] == 0) { - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); return; } cam_exposure = cam->raw_image[39]*2; @@ -2810,7 +2810,7 @@ static void restart_flicker(struct cam_data *cam) cam->exposure_status = EXPOSURE_NORMAL; } - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); } #undef FIRMWARE_VERSION @@ -3186,7 +3186,7 @@ static int cpia_open(struct inode *inode, struct file *file) if (!try_module_get(cam->ops->owner)) return -ENODEV; - down(&cam->busy_lock); + mutex_lock(&cam->busy_lock); err = -ENOMEM; if (!cam->raw_image) { cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE); @@ -3227,7 +3227,7 @@ static int cpia_open(struct inode *inode, struct file *file) ++cam->open_count; file->private_data = dev; - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return 0; oops: @@ -3239,7 +3239,7 @@ static int cpia_open(struct inode *inode, struct file *file) rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE); cam->raw_image = NULL; } - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); put_cam(cam->ops); return err; } @@ -3303,24 +3303,24 @@ static ssize_t cpia_read(struct file *file, char __user *buf, int err; /* make this _really_ smp and multithread-safe */ - if (down_interruptible(&cam->busy_lock)) + if (mutex_lock_interruptible(&cam->busy_lock)) return -EINTR; if (!buf) { DBG("buf NULL\n"); - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return -EINVAL; } if (!count) { DBG("count 0\n"); - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return 0; } if (!cam->ops) { DBG("ops NULL\n"); - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return -ENODEV; } @@ -3329,7 +3329,7 @@ static ssize_t cpia_read(struct file *file, char __user *buf, cam->mmap_kludge=0; if((err = fetch_frame(cam)) != 0) { DBG("ERROR from fetch_frame: %d\n", err); - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return err; } cam->decompressed_frame.state = FRAME_UNUSED; @@ -3338,17 +3338,17 @@ static ssize_t cpia_read(struct file *file, char __user *buf, if (cam->decompressed_frame.count > count) { DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count, (unsigned long) count); - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return -EFAULT; } if (copy_to_user(buf, cam->decompressed_frame.data, cam->decompressed_frame.count)) { DBG("copy_to_user failed\n"); - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return -EFAULT; } - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return cam->decompressed_frame.count; } @@ -3363,7 +3363,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, return -ENODEV; /* make this _really_ smp-safe */ - if (down_interruptible(&cam->busy_lock)) + if (mutex_lock_interruptible(&cam->busy_lock)) return -EINTR; //DBG("cpia_ioctl: %u\n", ioctlnr); @@ -3439,7 +3439,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, break; } - down(&cam->param_lock); + mutex_lock(&cam->param_lock); /* brightness, colour, contrast need no check 0-65535 */ cam->vp = *vp; /* update cam->params.colourParams */ @@ -3466,7 +3466,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, /* queue command to update camera */ cam->cmd_queue |= COMMAND_SETCOLOURPARAMS; - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n", vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour, vp->contrast); @@ -3501,13 +3501,13 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, /* we set the video window to something smaller or equal to what * is requested by the user??? */ - down(&cam->param_lock); + mutex_lock(&cam->param_lock); if (vw->width != cam->vw.width || vw->height != cam->vw.height) { int video_size = match_videosize(vw->width, vw->height); if (video_size < 0) { retval = -EINVAL; - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); break; } cam->video_size = video_size; @@ -3520,7 +3520,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, cam->cmd_queue |= COMMAND_SETFORMAT; } - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); /* setformat ignored by camera during streaming, * so stop/dispatch/start */ @@ -3682,7 +3682,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height); - down(&cam->param_lock); + mutex_lock(&cam->param_lock); cam->vc.x = vc->x; cam->vc.y = vc->y; @@ -3692,7 +3692,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, set_vw_size(cam); cam->cmd_queue |= COMMAND_SETFORMAT; - up(&cam->param_lock); + mutex_unlock(&cam->param_lock); /* setformat ignored by camera during streaming, * so stop/dispatch/start */ @@ -3736,7 +3736,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, break; } - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return retval; } @@ -3769,12 +3769,12 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma) return -ENODEV; /* make this _really_ smp-safe */ - if (down_interruptible(&cam->busy_lock)) + if (mutex_lock_interruptible(&cam->busy_lock)) return -EINTR; if (!cam->frame_buf) { /* we do lazy allocation */ if ((retval = allocate_frame_buf(cam))) { - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return retval; } } @@ -3783,7 +3783,7 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma) while (size > 0) { page = vmalloc_to_pfn((void *)pos); if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return -EAGAIN; } start += PAGE_SIZE; @@ -3795,7 +3795,7 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma) } DBG("cpia_mmap: %ld\n", size); - up(&cam->busy_lock); + mutex_unlock(&cam->busy_lock); return 0; } @@ -3936,8 +3936,8 @@ static void init_camera_struct(struct cam_data *cam, memset(cam, 0, sizeof(struct cam_data)); cam->ops = ops; - init_MUTEX(&cam->param_lock); - init_MUTEX(&cam->busy_lock); + mutex_init(&cam->param_lock); + mutex_init(&cam->busy_lock); reset_camera_struct(cam); diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h index f629b693ee6..de6678200a5 100644 --- a/drivers/media/video/cpia.h +++ b/drivers/media/video/cpia.h @@ -47,6 +47,7 @@ #include <linux/videodev.h> #include <linux/list.h> #include <linux/smp_lock.h> +#include <linux/mutex.h> struct cpia_camera_ops { @@ -246,7 +247,7 @@ enum v4l_camstates { struct cam_data { struct list_head cam_data_list; - struct semaphore busy_lock; /* guard against SMP multithreading */ + struct mutex busy_lock; /* guard against SMP multithreading */ struct cpia_camera_ops *ops; /* lowlevel driver operations */ void *lowlevel_data; /* private data for lowlevel driver */ u8 *raw_image; /* buffer for raw image data */ @@ -261,7 +262,7 @@ struct cam_data { u8 mainsFreq; /* for flicker control */ /* proc interface */ - struct semaphore param_lock; /* params lock for this camera */ + struct mutex param_lock; /* params lock for this camera */ struct cam_params params; /* camera settings */ struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */ diff --git a/drivers/media/video/cpia2/Kconfig b/drivers/media/video/cpia2/Kconfig new file mode 100644 index 00000000000..513cc092738 --- /dev/null +++ b/drivers/media/video/cpia2/Kconfig @@ -0,0 +1,9 @@ +config VIDEO_CPIA2 + tristate "CPiA2 Video For Linux" + depends on VIDEO_DEV && USB + ---help--- + This is the video4linux driver for cameras based on Vision's CPiA2 + (Colour Processor Interface ASIC), such as the Digital Blue QX5 + Microscope. If you have one of these cameras, say Y here + + This driver is also available as a module (cpia2). diff --git a/drivers/media/video/cpia2/Makefile b/drivers/media/video/cpia2/Makefile new file mode 100644 index 00000000000..828cf1b1df8 --- /dev/null +++ b/drivers/media/video/cpia2/Makefile @@ -0,0 +1,3 @@ +cpia2-objs := cpia2_v4l.o cpia2_usb.o cpia2_core.o + +obj-$(CONFIG_VIDEO_CPIA2) += cpia2.o diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h new file mode 100644 index 00000000000..95d3afa94a3 --- /dev/null +++ b/drivers/media/video/cpia2/cpia2.h @@ -0,0 +1,497 @@ +/**************************************************************************** + * + * Filename: cpia2.h + * + * Copyright 2001, STMicrolectronics, Inc. + * + * Contact: steve.miller@st.com + * + * Description: + * This is a USB driver for CPiA2 based video cameras. + * + * This driver is modelled on the cpia usb driver by + * Jochen Scharrlach and Johannes Erdfeldt. + * + * 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 __CPIA2_H__ +#define __CPIA2_H__ + +#include <linux/version.h> +#include <linux/videodev.h> +#include <linux/usb.h> +#include <linux/poll.h> + +#include "cpia2dev.h" +#include "cpia2_registers.h" + +/* define for verbose debug output */ +//#define _CPIA2_DEBUG_ + +#define CPIA2_MAJ_VER 2 +#define CPIA2_MIN_VER 0 +#define CPIA2_PATCH_VER 0 + +/*** + * Image defines + ***/ +#ifndef true +#define true 1 +#define false 0 +#endif + +/* Misc constants */ +#define ALLOW_CORRUPT 0 /* Causes collater to discard checksum */ + +/* USB Transfer mode */ +#define XFER_ISOC 0 +#define XFER_BULK 1 + +/* USB Alternates */ +#define USBIF_CMDONLY 0 +#define USBIF_BULK 1 +#define USBIF_ISO_1 2 /* 128 bytes/ms */ +#define USBIF_ISO_2 3 /* 384 bytes/ms */ +#define USBIF_ISO_3 4 /* 640 bytes/ms */ +#define USBIF_ISO_4 5 /* 768 bytes/ms */ +#define USBIF_ISO_5 6 /* 896 bytes/ms */ +#define USBIF_ISO_6 7 /* 1023 bytes/ms */ + +/* Flicker Modes */ +#define NEVER_FLICKER 0 +#define ANTI_FLICKER_ON 1 +#define FLICKER_60 60 +#define FLICKER_50 50 + +/* Debug flags */ +#define DEBUG_NONE 0 +#define DEBUG_REG 0x00000001 +#define DEBUG_DUMP_PATCH 0x00000002 +#define DEBUG_DUMP_REGS 0x00000004 + +/*** + * Video frame sizes + ***/ +enum { + VIDEOSIZE_VGA = 0, /* 640x480 */ + VIDEOSIZE_CIF, /* 352x288 */ + VIDEOSIZE_QVGA, /* 320x240 */ + VIDEOSIZE_QCIF, /* 176x144 */ + VIDEOSIZE_288_216, + VIDEOSIZE_256_192, + VIDEOSIZE_224_168, + VIDEOSIZE_192_144, +}; + +#define STV_IMAGE_CIF_ROWS 288 +#define STV_IMAGE_CIF_COLS 352 + +#define STV_IMAGE_QCIF_ROWS 144 +#define STV_IMAGE_QCIF_COLS 176 + +#define STV_IMAGE_VGA_ROWS 480 +#define STV_IMAGE_VGA_COLS 640 + +#define STV_IMAGE_QVGA_ROWS 240 +#define STV_IMAGE_QVGA_COLS 320 + +#define JPEG_MARKER_COM (1<<6) /* Comment segment */ + +/*** + * Enums + ***/ +/* Sensor types available with cpia2 asics */ +enum sensors { + CPIA2_SENSOR_410, + CPIA2_SENSOR_500 +}; + +/* Asic types available in the CPiA2 architecture */ +#define CPIA2_ASIC_672 0x67 + +/* Device types (stv672, stv676, etc) */ +#define DEVICE_STV_672 0x0001 +#define DEVICE_STV_676 0x0002 + +enum frame_status { + FRAME_EMPTY, + FRAME_READING, /* In the process of being grabbed into */ + FRAME_READY, /* Ready to be read */ + FRAME_ERROR, +}; + +/*** + * Register access (for USB request byte) + ***/ +enum { + CAMERAACCESS_SYSTEM = 0, + CAMERAACCESS_VC, + CAMERAACCESS_VP, + CAMERAACCESS_IDATA +}; + +#define CAMERAACCESS_TYPE_BLOCK 0x00 +#define CAMERAACCESS_TYPE_RANDOM 0x04 +#define CAMERAACCESS_TYPE_MASK 0x08 +#define CAMERAACCESS_TYPE_REPEAT 0x0C + +#define TRANSFER_READ 0 +#define TRANSFER_WRITE 1 + +#define DEFAULT_ALT USBIF_ISO_6 +#define DEFAULT_BRIGHTNESS 0x46 +#define DEFAULT_CONTRAST 0x93 +#define DEFAULT_SATURATION 0x7f +#define DEFAULT_TARGET_KB 0x30 + +/* Power state */ +#define HI_POWER_MODE CPIA2_SYSTEM_CONTROL_HIGH_POWER +#define LO_POWER_MODE CPIA2_SYSTEM_CONTROL_LOW_POWER + + +/******** + * Commands + *******/ +enum { + CPIA2_CMD_NONE = 0, + CPIA2_CMD_GET_VERSION, + CPIA2_CMD_GET_PNP_ID, + CPIA2_CMD_GET_ASIC_TYPE, + CPIA2_CMD_GET_SENSOR, + CPIA2_CMD_GET_VP_DEVICE, + CPIA2_CMD_GET_VP_BRIGHTNESS, + CPIA2_CMD_SET_VP_BRIGHTNESS, + CPIA2_CMD_GET_CONTRAST, + CPIA2_CMD_SET_CONTRAST, + CPIA2_CMD_GET_VP_SATURATION, + CPIA2_CMD_SET_VP_SATURATION, + CPIA2_CMD_GET_VP_GPIO_DIRECTION, + CPIA2_CMD_SET_VP_GPIO_DIRECTION, + CPIA2_CMD_GET_VP_GPIO_DATA, + CPIA2_CMD_SET_VP_GPIO_DATA, + CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, + CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, + CPIA2_CMD_GET_VC_MP_GPIO_DATA, + CPIA2_CMD_SET_VC_MP_GPIO_DATA, + CPIA2_CMD_ENABLE_PACKET_CTRL, + CPIA2_CMD_GET_FLICKER_MODES, + CPIA2_CMD_SET_FLICKER_MODES, + CPIA2_CMD_RESET_FIFO, /* clear fifo and enable stream block */ + CPIA2_CMD_SET_HI_POWER, + CPIA2_CMD_SET_LOW_POWER, + CPIA2_CMD_CLEAR_V2W_ERR, + CPIA2_CMD_SET_USER_MODE, + CPIA2_CMD_GET_USER_MODE, + CPIA2_CMD_FRAMERATE_REQ, + CPIA2_CMD_SET_COMPRESSION_STATE, + CPIA2_CMD_GET_WAKEUP, + CPIA2_CMD_SET_WAKEUP, + CPIA2_CMD_GET_PW_CONTROL, + CPIA2_CMD_SET_PW_CONTROL, + CPIA2_CMD_GET_SYSTEM_CTRL, + CPIA2_CMD_SET_SYSTEM_CTRL, + CPIA2_CMD_GET_VP_SYSTEM_STATE, + CPIA2_CMD_GET_VP_SYSTEM_CTRL, + CPIA2_CMD_SET_VP_SYSTEM_CTRL, + CPIA2_CMD_GET_VP_EXP_MODES, + CPIA2_CMD_SET_VP_EXP_MODES, + CPIA2_CMD_GET_DEVICE_CONFIG, + CPIA2_CMD_SET_DEVICE_CONFIG, + CPIA2_CMD_SET_SERIAL_ADDR, + CPIA2_CMD_SET_SENSOR_CR1, + CPIA2_CMD_GET_VC_CONTROL, + CPIA2_CMD_SET_VC_CONTROL, + CPIA2_CMD_SET_TARGET_KB, + CPIA2_CMD_SET_DEF_JPEG_OPT, + CPIA2_CMD_REHASH_VP4, + CPIA2_CMD_GET_USER_EFFECTS, + CPIA2_CMD_SET_USER_EFFECTS +}; + +enum user_cmd { + COMMAND_NONE = 0x00000001, + COMMAND_SET_FPS = 0x00000002, + COMMAND_SET_COLOR_PARAMS = 0x00000004, + COMMAND_GET_COLOR_PARAMS = 0x00000008, + COMMAND_SET_FORMAT = 0x00000010, /* size, etc */ + COMMAND_SET_FLICKER = 0x00000020 +}; + +/*** + * Some defines specific to the 676 chip + ***/ +#define CAMACC_CIF 0x01 +#define CAMACC_VGA 0x02 +#define CAMACC_QCIF 0x04 +#define CAMACC_QVGA 0x08 + + +struct cpia2_register { + u8 index; + u8 value; +}; + +struct cpia2_reg_mask { + u8 index; + u8 and_mask; + u8 or_mask; + u8 fill; +}; + +struct cpia2_command { + u32 command; + u8 req_mode; /* (Block or random) | registerBank */ + u8 reg_count; + u8 direction; + u8 start; + union reg_types { + struct cpia2_register registers[32]; + struct cpia2_reg_mask masks[16]; + u8 block_data[64]; + u8 *patch_data; /* points to function defined block */ + } buffer; +}; + +struct camera_params { + struct { + u8 firmware_revision_hi; /* For system register set (bank 0) */ + u8 firmware_revision_lo; + u8 asic_id; /* Video Compressor set (bank 1) */ + u8 asic_rev; + u8 vp_device_hi; /* Video Processor set (bank 2) */ + u8 vp_device_lo; + u8 sensor_flags; + u8 sensor_rev; + } version; + + struct { + u32 device_type; /* enumerated from vendor/product ids. + * Currently, either STV_672 or STV_676 */ + u16 vendor; + u16 product; + u16 device_revision; + } pnp_id; + + struct { + u8 brightness; /* CPIA2_VP_EXPOSURE_TARGET */ + u8 contrast; /* Note: this is CPIA2_VP_YRANGE */ + u8 saturation; /* CPIA2_VP_SATURATION */ + } color_params; + + struct { + u8 cam_register; + u8 flicker_mode_req; /* 1 if flicker on, else never flicker */ + int mains_frequency; + } flicker_control; + + struct { + u8 jpeg_options; + u8 creep_period; + u8 user_squeeze; + u8 inhibit_htables; + } compression; + + struct { + u8 ohsize; /* output image size */ + u8 ovsize; + u8 hcrop; /* cropping start_pos/4 */ + u8 vcrop; + u8 hphase; /* scaling registers */ + u8 vphase; + u8 hispan; + u8 vispan; + u8 hicrop; + u8 vicrop; + u8 hifraction; + u8 vifraction; + } image_size; + + struct { + int width; /* actual window width */ + int height; /* actual window height */ + } roi; + + struct { + u8 video_mode; + u8 frame_rate; + u8 video_size; /* Not a register, just a convenience for cropped sizes */ + u8 gpio_direction; + u8 gpio_data; + u8 system_ctrl; + u8 system_state; + u8 lowlight_boost; /* Bool: 0 = off, 1 = on */ + u8 device_config; + u8 exposure_modes; + u8 user_effects; + } vp_params; + + struct { + u8 pw_control; + u8 wakeup; + u8 vc_control; + u8 vc_mp_direction; + u8 vc_mp_data; + u8 target_kb; + } vc_params; + + struct { + u8 power_mode; + u8 system_ctrl; + u8 stream_mode; /* This is the current alternate for usb drivers */ + u8 allow_corrupt; + } camera_state; +}; + +#define NUM_SBUF 2 + +struct cpia2_sbuf { + char *data; + struct urb *urb; +}; + +struct framebuf { + struct timeval timestamp; + unsigned long seq; + int num; + int length; + int max_length; + volatile enum frame_status status; + u8 *data; + struct framebuf *next; +}; + +struct cpia2_fh { + enum v4l2_priority prio; + u8 mmapped; +}; + +struct camera_data { + /* locks */ + struct semaphore busy_lock; /* guard against SMP multithreading */ + struct v4l2_prio_state prio; + + /* camera status */ + volatile int present; /* Is the camera still present? */ + int open_count; /* # of process that have camera open */ + int first_image_seen; + u8 mains_freq; /* for flicker control */ + enum sensors sensor_type; + u8 flush; + u8 mmapped; + int streaming; /* 0 = no, 1 = yes */ + int xfer_mode; /* XFER_BULK or XFER_ISOC */ + struct camera_params params; /* camera settings */ + + /* v4l */ + int video_size; /* VIDEO_SIZE_ */ + struct video_device *vdev; /* v4l videodev */ + struct video_picture vp; /* v4l camera settings */ + struct video_window vw; /* v4l capture area */ + __u32 pixelformat; /* Format fourcc */ + + /* USB */ + struct usb_device *dev; + unsigned char iface; + unsigned int cur_alt; + unsigned int old_alt; + struct cpia2_sbuf sbuf[NUM_SBUF]; /* Double buffering */ + + wait_queue_head_t wq_stream; + + /* Buffering */ + u32 frame_size; + int num_frames; + unsigned long frame_count; + u8 *frame_buffer; /* frame buffer data */ + struct framebuf *buffers; + struct framebuf * volatile curbuff; + struct framebuf *workbuff; + + /* MJPEG Extension */ + int APPn; /* Number of APP segment to be written, must be 0..15 */ + int APP_len; /* Length of data in JPEG APPn segment */ + char APP_data[60]; /* Data in the JPEG APPn segment. */ + + int COM_len; /* Length of data in JPEG COM segment */ + char COM_data[60]; /* Data in JPEG COM segment */ +}; + +/* v4l */ +int cpia2_register_camera(struct camera_data *cam); +void cpia2_unregister_camera(struct camera_data *cam); + +/* core */ +int cpia2_reset_camera(struct camera_data *cam); +int cpia2_set_low_power(struct camera_data *cam); +void cpia2_dbg_dump_registers(struct camera_data *cam); +int cpia2_match_video_size(int width, int height); +void cpia2_set_camera_state(struct camera_data *cam); +void cpia2_save_camera_state(struct camera_data *cam); +void cpia2_set_color_params(struct camera_data *cam); +void cpia2_set_brightness(struct camera_data *cam, unsigned char value); +void cpia2_set_contrast(struct camera_data *cam, unsigned char value); +void cpia2_set_saturation(struct camera_data *cam, unsigned char value); +int cpia2_set_flicker_mode(struct camera_data *cam, int mode); +void cpia2_set_format(struct camera_data *cam); +int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd); +int cpia2_do_command(struct camera_data *cam, + unsigned int command, + unsigned char direction, unsigned char param); +struct camera_data *cpia2_init_camera_struct(void); +int cpia2_init_camera(struct camera_data *cam); +int cpia2_allocate_buffers(struct camera_data *cam); +void cpia2_free_buffers(struct camera_data *cam); +long cpia2_read(struct camera_data *cam, + char *buf, unsigned long count, int noblock); +unsigned int cpia2_poll(struct camera_data *cam, + struct file *filp, poll_table *wait); +int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma); +void cpia2_set_property_flip(struct camera_data *cam, int prop_val); +void cpia2_set_property_mirror(struct camera_data *cam, int prop_val); +int cpia2_set_target_kb(struct camera_data *cam, unsigned char value); +int cpia2_set_gpio(struct camera_data *cam, unsigned char setting); +int cpia2_set_fps(struct camera_data *cam, int framerate); + +/* usb */ +int cpia2_usb_init(void); +void cpia2_usb_cleanup(void); +int cpia2_usb_transfer_cmd(struct camera_data *cam, void *registers, + u8 request, u8 start, u8 count, u8 direction); +int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate); +int cpia2_usb_stream_stop(struct camera_data *cam); +int cpia2_usb_stream_pause(struct camera_data *cam); +int cpia2_usb_stream_resume(struct camera_data *cam); +int cpia2_usb_change_streaming_alternate(struct camera_data *cam, + unsigned int alt); + + +/* ----------------------- debug functions ---------------------- */ +#ifdef _CPIA2_DEBUG_ +#define ALOG(lev, fmt, args...) printk(lev "%s:%d %s(): " fmt, __FILE__, __LINE__, __func__, ## args) +#define LOG(fmt, args...) ALOG(KERN_INFO, fmt, ## args) +#define ERR(fmt, args...) ALOG(KERN_ERR, fmt, ## args) +#define DBG(fmt, args...) ALOG(KERN_DEBUG, fmt, ## args) +#else +#define ALOG(fmt,args...) printk(fmt,##args) +#define LOG(fmt,args...) ALOG(KERN_INFO "cpia2: "fmt,##args) +#define ERR(fmt,args...) ALOG(KERN_ERR "cpia2: "fmt,##args) +#define DBG(fmn,args...) do {} while(0) +#endif +/* No function or lineno, for shorter lines */ +#define KINFO(fmt, args...) printk(KERN_INFO fmt,##args) + +#endif diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c new file mode 100644 index 00000000000..5dfb242d5b8 --- /dev/null +++ b/drivers/media/video/cpia2/cpia2_core.c @@ -0,0 +1,2525 @@ +/**************************************************************************** + * + * Filename: cpia2_core.c + * + * Copyright 2001, STMicrolectronics, Inc. + * Contact: steve.miller@st.com + * + * Description: + * This is a USB driver for CPia2 based video cameras. + * The infrastructure of this driver is based on the cpia usb driver by + * Jochen Scharrlach and Johannes Erdfeldt. + * + * 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. + * + * Stripped of 2.4 stuff ready for main kernel submit by + * Alan Cox <alan@redhat.com> + * + ****************************************************************************/ + +#include "cpia2.h" + +#include <linux/slab.h> +#include <linux/vmalloc.h> + +//#define _CPIA2_DEBUG_ + +#include "cpia2patch.h" + +#ifdef _CPIA2_DEBUG_ + +static const char *block_name[] = { + "System", + "VC", + "VP", + "IDATA" +}; +#endif + +static unsigned int debugs_on = 0;//DEBUG_REG; + + +/****************************************************************************** + * + * Forward Declarations + * + *****************************************************************************/ +static int apply_vp_patch(struct camera_data *cam); +static int set_default_user_mode(struct camera_data *cam); +static int set_vw_size(struct camera_data *cam, int size); +static int configure_sensor(struct camera_data *cam, + int reqwidth, int reqheight); +static int config_sensor_410(struct camera_data *cam, + int reqwidth, int reqheight); +static int config_sensor_500(struct camera_data *cam, + int reqwidth, int reqheight); +static int set_all_properties(struct camera_data *cam); +static void get_color_params(struct camera_data *cam); +static void wake_system(struct camera_data *cam); +static void set_lowlight_boost(struct camera_data *cam); +static void reset_camera_struct(struct camera_data *cam); +static int cpia2_set_high_power(struct camera_data *cam); + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the + * area and marking the pages as reserved. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long kva, ret; + + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ + ret = __pa(kva); + return ret; +} + +static void *rvmalloc(unsigned long size) +{ + void *mem; + unsigned long adr; + + /* Round it off to PAGE_SIZE */ + size = PAGE_ALIGN(size); + + mem = vmalloc_32(size); + if (!mem) + return NULL; + + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr = (unsigned long) mem; + + while ((long)size > 0) { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + return mem; +} + +static void rvfree(void *mem, unsigned long size) +{ + unsigned long adr; + + if (!mem) + return; + + size = PAGE_ALIGN(size); + + adr = (unsigned long) mem; + while ((long)size > 0) { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + vfree(mem); +} + +/****************************************************************************** + * + * cpia2_do_command + * + * Send an arbitrary command to the camera. For commands that read from + * the camera, copy the buffers into the proper param structures. + *****************************************************************************/ +int cpia2_do_command(struct camera_data *cam, + u32 command, u8 direction, u8 param) +{ + int retval = 0; + struct cpia2_command cmd; + unsigned int device = cam->params.pnp_id.device_type; + + cmd.command = command; + cmd.reg_count = 2; /* default */ + cmd.direction = direction; + + /*** + * Set up the command. + ***/ + switch (command) { + case CPIA2_CMD_GET_VERSION: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.start = CPIA2_SYSTEM_DEVICE_HI; + break; + case CPIA2_CMD_GET_PNP_ID: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 8; + cmd.start = CPIA2_SYSTEM_DESCRIP_VID_HI; + break; + case CPIA2_CMD_GET_ASIC_TYPE: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.start = CPIA2_VC_ASIC_ID; + break; + case CPIA2_CMD_GET_SENSOR: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.start = CPIA2_VP_SENSOR_FLAGS; + break; + case CPIA2_CMD_GET_VP_DEVICE: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.start = CPIA2_VP_DEVICEH; + break; + case CPIA2_CMD_SET_VP_BRIGHTNESS: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_BRIGHTNESS: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + if (device == DEVICE_STV_672) + cmd.start = CPIA2_VP4_EXPOSURE_TARGET; + else + cmd.start = CPIA2_VP5_EXPOSURE_TARGET; + break; + case CPIA2_CMD_SET_CONTRAST: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_CONTRAST: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_YRANGE; + break; + case CPIA2_CMD_SET_VP_SATURATION: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_SATURATION: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + if (device == DEVICE_STV_672) + cmd.start = CPIA2_VP_SATURATION; + else + cmd.start = CPIA2_VP5_MCUVSATURATION; + break; + case CPIA2_CMD_SET_VP_GPIO_DATA: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_GPIO_DATA: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_GPIO_DATA; + break; + case CPIA2_CMD_SET_VP_GPIO_DIRECTION: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_GPIO_DIRECTION: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_GPIO_DIRECTION; + break; + case CPIA2_CMD_SET_VC_MP_GPIO_DATA: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VC_MP_GPIO_DATA: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.start = CPIA2_VC_MP_DATA; + break; + case CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.start = CPIA2_VC_MP_DIR; + break; + case CPIA2_CMD_ENABLE_PACKET_CTRL: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.start = CPIA2_SYSTEM_INT_PACKET_CTRL; + cmd.reg_count = 1; + cmd.buffer.block_data[0] = param; + break; + case CPIA2_CMD_SET_FLICKER_MODES: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_FLICKER_MODES: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_FLICKER_MODES; + break; + case CPIA2_CMD_RESET_FIFO: /* clear fifo and enable stream block */ + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.reg_count = 2; + cmd.start = 0; + cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL; + cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC | + CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT; + cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL; + cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC | + CPIA2_VC_ST_CTRL_DST_USB | + CPIA2_VC_ST_CTRL_EOF_DETECT | + CPIA2_VC_ST_CTRL_FIFO_ENABLE; + break; + case CPIA2_CMD_SET_HI_POWER: + cmd.req_mode = + CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM; + cmd.reg_count = 2; + cmd.buffer.registers[0].index = + CPIA2_SYSTEM_SYSTEM_CONTROL; + cmd.buffer.registers[1].index = + CPIA2_SYSTEM_SYSTEM_CONTROL; + cmd.buffer.registers[0].value = CPIA2_SYSTEM_CONTROL_CLEAR_ERR; + cmd.buffer.registers[1].value = + CPIA2_SYSTEM_CONTROL_HIGH_POWER; + break; + case CPIA2_CMD_SET_LOW_POWER: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 1; + cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; + cmd.buffer.block_data[0] = 0; + break; + case CPIA2_CMD_CLEAR_V2W_ERR: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 1; + cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; + cmd.buffer.block_data[0] = CPIA2_SYSTEM_CONTROL_CLEAR_ERR; + break; + case CPIA2_CMD_SET_USER_MODE: /* Then fall through */ + cmd.buffer.block_data[0] = param; + case CPIA2_CMD_GET_USER_MODE: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + if (device == DEVICE_STV_672) + cmd.start = CPIA2_VP4_USER_MODE; + else + cmd.start = CPIA2_VP5_USER_MODE; + break; + case CPIA2_CMD_FRAMERATE_REQ: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + if (device == DEVICE_STV_672) + cmd.start = CPIA2_VP4_FRAMERATE_REQUEST; + else + cmd.start = CPIA2_VP5_FRAMERATE_REQUEST; + cmd.buffer.block_data[0] = param; + break; + case CPIA2_CMD_SET_WAKEUP: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_WAKEUP: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.start = CPIA2_VC_WAKEUP; + break; + case CPIA2_CMD_SET_PW_CONTROL: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_PW_CONTROL: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.start = CPIA2_VC_PW_CTRL; + break; + case CPIA2_CMD_GET_VP_SYSTEM_STATE: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_SYSTEMSTATE; + break; + case CPIA2_CMD_SET_SYSTEM_CTRL: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_SYSTEM_CTRL: + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 1; + cmd.start = CPIA2_SYSTEM_SYSTEM_CONTROL; + break; + case CPIA2_CMD_SET_VP_SYSTEM_CTRL: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_SYSTEM_CTRL: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_SYSTEMCTRL; + break; + case CPIA2_CMD_SET_VP_EXP_MODES: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VP_EXP_MODES: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_EXPOSURE_MODES; + break; + case CPIA2_CMD_SET_DEVICE_CONFIG: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_DEVICE_CONFIG: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_DEVICE_CONFIG; + break; + case CPIA2_CMD_SET_SERIAL_ADDR: + cmd.buffer.block_data[0] = param; + cmd.req_mode = + CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 1; + cmd.start = CPIA2_SYSTEM_VP_SERIAL_ADDR; + break; + case CPIA2_CMD_SET_SENSOR_CR1: + cmd.buffer.block_data[0] = param; + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_SENSOR_CR1; + break; + case CPIA2_CMD_SET_VC_CONTROL: + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_VC_CONTROL: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.start = CPIA2_VC_VC_CTRL; + break; + case CPIA2_CMD_SET_TARGET_KB: + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.reg_count = 1; + cmd.buffer.registers[0].index = CPIA2_VC_VC_TARGET_KB; + cmd.buffer.registers[0].value = param; + break; + case CPIA2_CMD_SET_DEF_JPEG_OPT: + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.reg_count = 4; + cmd.buffer.registers[0].index = CPIA2_VC_VC_JPEG_OPT; + cmd.buffer.registers[0].value = + CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE; + cmd.buffer.registers[1].index = CPIA2_VC_VC_USER_SQUEEZE; + cmd.buffer.registers[1].value = 20; + cmd.buffer.registers[2].index = CPIA2_VC_VC_CREEP_PERIOD; + cmd.buffer.registers[2].value = 2; + cmd.buffer.registers[3].index = CPIA2_VC_VC_JPEG_OPT; + cmd.buffer.registers[3].value = CPIA2_VC_VC_JPEG_OPT_DEFAULT; + break; + case CPIA2_CMD_REHASH_VP4: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + cmd.start = CPIA2_VP_REHASH_VALUES; + cmd.buffer.block_data[0] = param; + break; + case CPIA2_CMD_SET_USER_EFFECTS: /* Note: Be careful with this as + this register can also affect + flicker modes */ + cmd.buffer.block_data[0] = param; /* Then fall through */ + case CPIA2_CMD_GET_USER_EFFECTS: + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 1; + if (device == DEVICE_STV_672) + cmd.start = CPIA2_VP4_USER_EFFECTS; + else + cmd.start = CPIA2_VP5_USER_EFFECTS; + break; + default: + LOG("DoCommand received invalid command\n"); + return -EINVAL; + } + + retval = cpia2_send_command(cam, &cmd); + if (retval) { + return retval; + } + + /*** + * Now copy any results from a read into the appropriate param struct. + ***/ + switch (command) { + case CPIA2_CMD_GET_VERSION: + cam->params.version.firmware_revision_hi = + cmd.buffer.block_data[0]; + cam->params.version.firmware_revision_lo = + cmd.buffer.block_data[1]; + break; + case CPIA2_CMD_GET_PNP_ID: + cam->params.pnp_id.vendor = (cmd.buffer.block_data[0] << 8) | + cmd.buffer.block_data[1]; + cam->params.pnp_id.product = (cmd.buffer.block_data[2] << 8) | + cmd.buffer.block_data[3]; + cam->params.pnp_id.device_revision = + (cmd.buffer.block_data[4] << 8) | + cmd.buffer.block_data[5]; + if (cam->params.pnp_id.vendor == 0x553) { + if (cam->params.pnp_id.product == 0x100) { + cam->params.pnp_id.device_type = DEVICE_STV_672; + } else if (cam->params.pnp_id.product == 0x140 || + cam->params.pnp_id.product == 0x151) { + cam->params.pnp_id.device_type = DEVICE_STV_676; + } + } + break; + case CPIA2_CMD_GET_ASIC_TYPE: + cam->params.version.asic_id = cmd.buffer.block_data[0]; + cam->params.version.asic_rev = cmd.buffer.block_data[1]; + break; + case CPIA2_CMD_GET_SENSOR: + cam->params.version.sensor_flags = cmd.buffer.block_data[0]; + cam->params.version.sensor_rev = cmd.buffer.block_data[1]; + break; + case CPIA2_CMD_GET_VP_DEVICE: + cam->params.version.vp_device_hi = cmd.buffer.block_data[0]; + cam->params.version.vp_device_lo = cmd.buffer.block_data[1]; + break; + case CPIA2_CMD_GET_VP_BRIGHTNESS: + cam->params.color_params.brightness = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_CONTRAST: + cam->params.color_params.contrast = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_SATURATION: + cam->params.color_params.saturation = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_GPIO_DATA: + cam->params.vp_params.gpio_data = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_GPIO_DIRECTION: + cam->params.vp_params.gpio_direction = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION: + cam->params.vc_params.vc_mp_direction =cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VC_MP_GPIO_DATA: + cam->params.vc_params.vc_mp_data = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_FLICKER_MODES: + cam->params.flicker_control.cam_register = + cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_WAKEUP: + cam->params.vc_params.wakeup = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_PW_CONTROL: + cam->params.vc_params.pw_control = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_SYSTEM_CTRL: + cam->params.camera_state.system_ctrl = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_SYSTEM_STATE: + cam->params.vp_params.system_state = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_SYSTEM_CTRL: + cam->params.vp_params.system_ctrl = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VP_EXP_MODES: + cam->params.vp_params.exposure_modes = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_DEVICE_CONFIG: + cam->params.vp_params.device_config = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_VC_CONTROL: + cam->params.vc_params.vc_control = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_USER_MODE: + cam->params.vp_params.video_mode = cmd.buffer.block_data[0]; + break; + case CPIA2_CMD_GET_USER_EFFECTS: + cam->params.vp_params.user_effects = cmd.buffer.block_data[0]; + break; + default: + break; + } + return retval; +} + +/****************************************************************************** + * + * cpia2_send_command + * + *****************************************************************************/ +int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd) +{ + u8 count; + u8 start; + u8 block_index; + u8 *buffer; + int retval; + const char* dir; + + if (cmd->direction == TRANSFER_WRITE) { + dir = "Write"; + } else { + dir = "Read"; + } + + block_index = cmd->req_mode & 0x03; + + switch (cmd->req_mode & 0x0c) { + case CAMERAACCESS_TYPE_RANDOM: + count = cmd->reg_count * sizeof(struct cpia2_register); + start = 0; + buffer = (u8 *) & cmd->buffer; + if (debugs_on & DEBUG_REG) + DBG("%s Random: Register block %s\n", dir, + block_name[block_index]); + break; + case CAMERAACCESS_TYPE_BLOCK: + count = cmd->reg_count; + start = cmd->start; + buffer = cmd->buffer.block_data; + if (debugs_on & DEBUG_REG) + DBG("%s Block: Register block %s\n", dir, + block_name[block_index]); + break; + case CAMERAACCESS_TYPE_MASK: + count = cmd->reg_count * sizeof(struct cpia2_reg_mask); + start = 0; + buffer = (u8 *) & cmd->buffer; + if (debugs_on & DEBUG_REG) + DBG("%s Mask: Register block %s\n", dir, + block_name[block_index]); + break; + case CAMERAACCESS_TYPE_REPEAT: /* For patch blocks only */ + count = cmd->reg_count; + start = cmd->start; + buffer = cmd->buffer.block_data; + if (debugs_on & DEBUG_REG) + DBG("%s Repeat: Register block %s\n", dir, + block_name[block_index]); + break; + default: + LOG("%s: invalid request mode\n",__FUNCTION__); + return -EINVAL; + } + + retval = cpia2_usb_transfer_cmd(cam, + buffer, + cmd->req_mode, + start, count, cmd->direction); +#ifdef _CPIA2_DEBUG_ + if (debugs_on & DEBUG_REG) { + int i; + for (i = 0; i < cmd->reg_count; i++) { + if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_BLOCK) + KINFO("%s Block: [0x%02X] = 0x%02X\n", + dir, start + i, buffer[i]); + if((cmd->req_mode & 0x0c) == CAMERAACCESS_TYPE_RANDOM) + KINFO("%s Random: [0x%02X] = 0x%02X\n", + dir, cmd->buffer.registers[i].index, + cmd->buffer.registers[i].value); + } + } +#endif + + return retval; +}; + +/************* + * Functions to implement camera functionality + *************/ +/****************************************************************************** + * + * cpia2_get_version_info + * + *****************************************************************************/ +static void cpia2_get_version_info(struct camera_data *cam) +{ + cpia2_do_command(cam, CPIA2_CMD_GET_VERSION, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_PNP_ID, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_ASIC_TYPE, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_SENSOR, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_VP_DEVICE, TRANSFER_READ, 0); +} + +/****************************************************************************** + * + * cpia2_reset_camera + * + * Called at least during the open process, sets up initial params. + *****************************************************************************/ +int cpia2_reset_camera(struct camera_data *cam) +{ + u8 tmp_reg; + int retval = 0; + int i; + struct cpia2_command cmd; + + /*** + * VC setup + ***/ + retval = configure_sensor(cam, + cam->params.roi.width, + cam->params.roi.height); + if (retval < 0) { + ERR("Couldn't configure sensor, error=%d\n", retval); + return retval; + } + + /* Clear FIFO and route/enable stream block */ + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.direction = TRANSFER_WRITE; + cmd.reg_count = 2; + cmd.buffer.registers[0].index = CPIA2_VC_ST_CTRL; + cmd.buffer.registers[0].value = CPIA2_VC_ST_CTRL_SRC_VC | + CPIA2_VC_ST_CTRL_DST_USB | CPIA2_VC_ST_CTRL_EOF_DETECT; + cmd.buffer.registers[1].index = CPIA2_VC_ST_CTRL; + cmd.buffer.registers[1].value = CPIA2_VC_ST_CTRL_SRC_VC | + CPIA2_VC_ST_CTRL_DST_USB | + CPIA2_VC_ST_CTRL_EOF_DETECT | CPIA2_VC_ST_CTRL_FIFO_ENABLE; + + cpia2_send_command(cam, &cmd); + + cpia2_set_high_power(cam); + + if (cam->params.pnp_id.device_type == DEVICE_STV_672) { + /* Enable button notification */ + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_SYSTEM; + cmd.buffer.registers[0].index = CPIA2_SYSTEM_INT_PACKET_CTRL; + cmd.buffer.registers[0].value = + CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX; + cmd.reg_count = 1; + cpia2_send_command(cam, &cmd); + } + + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */ + + if (cam->params.pnp_id.device_type == DEVICE_STV_672) + retval = apply_vp_patch(cam); + + /* wait for vp to go to sleep */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */ + + /*** + * If this is a 676, apply VP5 fixes before we start streaming + ***/ + if (cam->params.pnp_id.device_type == DEVICE_STV_676) { + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; + + /* The following writes improve the picture */ + cmd.buffer.registers[0].index = CPIA2_VP5_MYBLACK_LEVEL; + cmd.buffer.registers[0].value = 0; /* reduce from the default + * rec 601 pedestal of 16 */ + cmd.buffer.registers[1].index = CPIA2_VP5_MCYRANGE; + cmd.buffer.registers[1].value = 0x92; /* increase from 100% to + * (256/256 - 31) to fill + * available range */ + cmd.buffer.registers[2].index = CPIA2_VP5_MYCEILING; + cmd.buffer.registers[2].value = 0xFF; /* Increase from the + * default rec 601 ceiling + * of 240 */ + cmd.buffer.registers[3].index = CPIA2_VP5_MCUVSATURATION; + cmd.buffer.registers[3].value = 0xFF; /* Increase from the rec + * 601 100% level (128) + * to 145-192 */ + cmd.buffer.registers[4].index = CPIA2_VP5_ANTIFLKRSETUP; + cmd.buffer.registers[4].value = 0x80; /* Inhibit the + * anti-flicker */ + + /* The following 4 writes are a fix to allow QVGA to work at 30 fps */ + cmd.buffer.registers[5].index = CPIA2_VP_RAM_ADDR_H; + cmd.buffer.registers[5].value = 0x01; + cmd.buffer.registers[6].index = CPIA2_VP_RAM_ADDR_L; + cmd.buffer.registers[6].value = 0xE3; + cmd.buffer.registers[7].index = CPIA2_VP_RAM_DATA; + cmd.buffer.registers[7].value = 0x02; + cmd.buffer.registers[8].index = CPIA2_VP_RAM_DATA; + cmd.buffer.registers[8].value = 0xFC; + + cmd.direction = TRANSFER_WRITE; + cmd.reg_count = 9; + + cpia2_send_command(cam, &cmd); + } + + /* Activate all settings and start the data stream */ + /* Set user mode */ + set_default_user_mode(cam); + + /* Give VP time to wake up */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(100 * HZ / 1000); /* wait for 100 msecs */ + + set_all_properties(cam); + + cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0); + DBG("After SetAllProperties(cam), user mode is 0x%0X\n", + cam->params.vp_params.video_mode); + + /*** + * Set audio regulator off. This and the code to set the compresison + * state are too complex to form a CPIA2_CMD_, and seem to be somewhat + * intertwined. This stuff came straight from the windows driver. + ***/ + /* Turn AutoExposure off in VP and enable the serial bridge to the sensor */ + cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0); + tmp_reg = cam->params.vp_params.system_ctrl; + cmd.buffer.registers[0].value = tmp_reg & + (tmp_reg & (CPIA2_VP_SYSTEMCTRL_HK_CONTROL ^ 0xFF)); + + cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0); + cmd.buffer.registers[1].value = cam->params.vp_params.device_config | + CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE; + cmd.buffer.registers[0].index = CPIA2_VP_SYSTEMCTRL; + cmd.buffer.registers[1].index = CPIA2_VP_DEVICE_CONFIG; + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; + cmd.reg_count = 2; + cmd.direction = TRANSFER_WRITE; + cmd.start = 0; + cpia2_send_command(cam, &cmd); + + /* Set the correct I2C address in the CPiA-2 system register */ + cpia2_do_command(cam, + CPIA2_CMD_SET_SERIAL_ADDR, + TRANSFER_WRITE, + CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR); + + /* Now have sensor access - set bit to turn the audio regulator off */ + cpia2_do_command(cam, + CPIA2_CMD_SET_SENSOR_CR1, + TRANSFER_WRITE, CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR); + + /* Set the correct I2C address in the CPiA-2 system register */ + if (cam->params.pnp_id.device_type == DEVICE_STV_672) + cpia2_do_command(cam, + CPIA2_CMD_SET_SERIAL_ADDR, + TRANSFER_WRITE, + CPIA2_SYSTEM_VP_SERIAL_ADDR_VP); // 0x88 + else + cpia2_do_command(cam, + CPIA2_CMD_SET_SERIAL_ADDR, + TRANSFER_WRITE, + CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP); // 0x8a + + /* increase signal drive strength */ + if (cam->params.pnp_id.device_type == DEVICE_STV_676) + cpia2_do_command(cam, + CPIA2_CMD_SET_VP_EXP_MODES, + TRANSFER_WRITE, + CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP); + + /* Start autoexposure */ + cpia2_do_command(cam, CPIA2_CMD_GET_DEVICE_CONFIG, TRANSFER_READ, 0); + cmd.buffer.registers[0].value = cam->params.vp_params.device_config & + (CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE ^ 0xFF); + + cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_CTRL, TRANSFER_READ, 0); + cmd.buffer.registers[1].value = + cam->params.vp_params.system_ctrl | CPIA2_VP_SYSTEMCTRL_HK_CONTROL; + + cmd.buffer.registers[0].index = CPIA2_VP_DEVICE_CONFIG; + cmd.buffer.registers[1].index = CPIA2_VP_SYSTEMCTRL; + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VP; + cmd.reg_count = 2; + cmd.direction = TRANSFER_WRITE; + + cpia2_send_command(cam, &cmd); + + /* Set compression state */ + cpia2_do_command(cam, CPIA2_CMD_GET_VC_CONTROL, TRANSFER_READ, 0); + if (cam->params.compression.inhibit_htables) { + tmp_reg = cam->params.vc_params.vc_control | + CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES; + } else { + tmp_reg = cam->params.vc_params.vc_control & + ~CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES; + } + cpia2_do_command(cam, CPIA2_CMD_SET_VC_CONTROL, TRANSFER_WRITE,tmp_reg); + + /* Set target size (kb) on vc */ + cpia2_do_command(cam, CPIA2_CMD_SET_TARGET_KB, + TRANSFER_WRITE, cam->params.vc_params.target_kb); + + /* Wiggle VC Reset */ + /*** + * First read and wait a bit. + ***/ + for (i = 0; i < 50; i++) { + cpia2_do_command(cam, CPIA2_CMD_GET_PW_CONTROL, + TRANSFER_READ, 0); + } + + tmp_reg = cam->params.vc_params.pw_control; + tmp_reg &= ~CPIA2_VC_PW_CTRL_VC_RESET_N; + + cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg); + + tmp_reg |= CPIA2_VC_PW_CTRL_VC_RESET_N; + cpia2_do_command(cam, CPIA2_CMD_SET_PW_CONTROL, TRANSFER_WRITE,tmp_reg); + + cpia2_do_command(cam, CPIA2_CMD_SET_DEF_JPEG_OPT, TRANSFER_WRITE, 0); + + cpia2_do_command(cam, CPIA2_CMD_GET_USER_MODE, TRANSFER_READ, 0); + DBG("After VC RESET, user mode is 0x%0X\n", + cam->params.vp_params.video_mode); + + return retval; +} + +/****************************************************************************** + * + * cpia2_set_high_power + * + *****************************************************************************/ +static int cpia2_set_high_power(struct camera_data *cam) +{ + int i; + for (i = 0; i <= 50; i++) { + /* Read system status */ + cpia2_do_command(cam,CPIA2_CMD_GET_SYSTEM_CTRL,TRANSFER_READ,0); + + /* If there is an error, clear it */ + if(cam->params.camera_state.system_ctrl & + CPIA2_SYSTEM_CONTROL_V2W_ERR) + cpia2_do_command(cam, CPIA2_CMD_CLEAR_V2W_ERR, + TRANSFER_WRITE, 0); + + /* Try to set high power mode */ + cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, + TRANSFER_WRITE, 1); + + /* Try to read something in VP to check if everything is awake */ + cpia2_do_command(cam, CPIA2_CMD_GET_VP_SYSTEM_STATE, + TRANSFER_READ, 0); + if (cam->params.vp_params.system_state & + CPIA2_VP_SYSTEMSTATE_HK_ALIVE) { + break; + } else if (i == 50) { + cam->params.camera_state.power_mode = LO_POWER_MODE; + ERR("Camera did not wake up\n"); + return -EIO; + } + } + + DBG("System now in high power state\n"); + cam->params.camera_state.power_mode = HI_POWER_MODE; + return 0; +} + +/****************************************************************************** + * + * cpia2_set_low_power + * + *****************************************************************************/ +int cpia2_set_low_power(struct camera_data *cam) +{ + cam->params.camera_state.power_mode = LO_POWER_MODE; + cpia2_do_command(cam, CPIA2_CMD_SET_SYSTEM_CTRL, TRANSFER_WRITE, 0); + return 0; +} + +/****************************************************************************** + * + * apply_vp_patch + * + *****************************************************************************/ +static int apply_vp_patch(struct camera_data *cam) +{ + int i, j; + struct cpia2_command cmd; + + cmd.req_mode = CAMERAACCESS_TYPE_REPEAT | CAMERAACCESS_VP; + cmd.direction = TRANSFER_WRITE; + + for (i = 0; i < PATCH_DATA_SIZE; i++) { + for (j = 0; j < patch_data[i].count; j++) { + cmd.buffer.block_data[j] = patch_data[i].data[j]; + } + + cmd.start = patch_data[i].reg; + cmd.reg_count = patch_data[i].count; + cpia2_send_command(cam, &cmd); + } + + return 0; +} + +/****************************************************************************** + * + * set_default_user_mode + * + *****************************************************************************/ +static int set_default_user_mode(struct camera_data *cam) +{ + unsigned char user_mode; + unsigned char frame_rate; + int width = cam->params.roi.width; + int height = cam->params.roi.height; + + switch (cam->params.version.sensor_flags) { + case CPIA2_VP_SENSOR_FLAGS_404: + case CPIA2_VP_SENSOR_FLAGS_407: + case CPIA2_VP_SENSOR_FLAGS_409: + case CPIA2_VP_SENSOR_FLAGS_410: + if ((width > STV_IMAGE_QCIF_COLS) + || (height > STV_IMAGE_QCIF_ROWS)) { + user_mode = CPIA2_VP_USER_MODE_CIF; + } else { + user_mode = CPIA2_VP_USER_MODE_QCIFDS; + } + frame_rate = CPIA2_VP_FRAMERATE_30; + break; + case CPIA2_VP_SENSOR_FLAGS_500: + if ((width > STV_IMAGE_CIF_COLS) + || (height > STV_IMAGE_CIF_ROWS)) { + user_mode = CPIA2_VP_USER_MODE_VGA; + } else { + user_mode = CPIA2_VP_USER_MODE_QVGADS; + } + if (cam->params.pnp_id.device_type == DEVICE_STV_672) + frame_rate = CPIA2_VP_FRAMERATE_15; + else + frame_rate = CPIA2_VP_FRAMERATE_30; + break; + default: + LOG("%s: Invalid sensor flag value 0x%0X\n",__FUNCTION__, + cam->params.version.sensor_flags); + return -EINVAL; + } + + DBG("Sensor flag = 0x%0x, user mode = 0x%0x, frame rate = 0x%X\n", + cam->params.version.sensor_flags, user_mode, frame_rate); + cpia2_do_command(cam, CPIA2_CMD_SET_USER_MODE, TRANSFER_WRITE, + user_mode); + if(cam->params.vp_params.frame_rate > 0 && + frame_rate > cam->params.vp_params.frame_rate) + frame_rate = cam->params.vp_params.frame_rate; + + cpia2_set_fps(cam, frame_rate); + +// if (cam->params.pnp_id.device_type == DEVICE_STV_676) +// cpia2_do_command(cam, +// CPIA2_CMD_SET_VP_SYSTEM_CTRL, +// TRANSFER_WRITE, +// CPIA2_VP_SYSTEMCTRL_HK_CONTROL | +// CPIA2_VP_SYSTEMCTRL_POWER_CONTROL); + + return 0; +} + +/****************************************************************************** + * + * cpia2_match_video_size + * + * return the best match, where 'best' is as always + * the largest that is not bigger than what is requested. + *****************************************************************************/ +int cpia2_match_video_size(int width, int height) +{ + if (width >= STV_IMAGE_VGA_COLS && height >= STV_IMAGE_VGA_ROWS) + return VIDEOSIZE_VGA; + + if (width >= STV_IMAGE_CIF_COLS && height >= STV_IMAGE_CIF_ROWS) + return VIDEOSIZE_CIF; + + if (width >= STV_IMAGE_QVGA_COLS && height >= STV_IMAGE_QVGA_ROWS) + return VIDEOSIZE_QVGA; + + if (width >= 288 && height >= 216) + return VIDEOSIZE_288_216; + + if (width >= 256 && height >= 192) + return VIDEOSIZE_256_192; + + if (width >= 224 && height >= 168) + return VIDEOSIZE_224_168; + + if (width >= 192 && height >= 144) + return VIDEOSIZE_192_144; + + if (width >= STV_IMAGE_QCIF_COLS && height >= STV_IMAGE_QCIF_ROWS) + return VIDEOSIZE_QCIF; + + return -1; +} + +/****************************************************************************** + * + * SetVideoSize + * + *****************************************************************************/ +static int set_vw_size(struct camera_data *cam, int size) +{ + int retval = 0; + + cam->params.vp_params.video_size = size; + + switch (size) { + case VIDEOSIZE_VGA: + DBG("Setting size to VGA\n"); + cam->params.roi.width = STV_IMAGE_VGA_COLS; + cam->params.roi.height = STV_IMAGE_VGA_ROWS; + cam->vw.width = STV_IMAGE_VGA_COLS; + cam->vw.height = STV_IMAGE_VGA_ROWS; + break; + case VIDEOSIZE_CIF: + DBG("Setting size to CIF\n"); + cam->params.roi.width = STV_IMAGE_CIF_COLS; + cam->params.roi.height = STV_IMAGE_CIF_ROWS; + cam->vw.width = STV_IMAGE_CIF_COLS; + cam->vw.height = STV_IMAGE_CIF_ROWS; + break; + case VIDEOSIZE_QVGA: + DBG("Setting size to QVGA\n"); + cam->params.roi.width = STV_IMAGE_QVGA_COLS; + cam->params.roi.height = STV_IMAGE_QVGA_ROWS; + cam->vw.width = STV_IMAGE_QVGA_COLS; + cam->vw.height = STV_IMAGE_QVGA_ROWS; + break; + case VIDEOSIZE_288_216: + cam->params.roi.width = 288; + cam->params.roi.height = 216; + cam->vw.width = 288; + cam->vw.height = 216; + break; + case VIDEOSIZE_256_192: + cam->vw.width = 256; + cam->vw.height = 192; + cam->params.roi.width = 256; + cam->params.roi.height = 192; + break; + case VIDEOSIZE_224_168: + cam->vw.width = 224; + cam->vw.height = 168; + cam->params.roi.width = 224; + cam->params.roi.height = 168; + break; + case VIDEOSIZE_192_144: + cam->vw.width = 192; + cam->vw.height = 144; + cam->params.roi.width = 192; + cam->params.roi.height = 144; + break; + case VIDEOSIZE_QCIF: + DBG("Setting size to QCIF\n"); + cam->params.roi.width = STV_IMAGE_QCIF_COLS; + cam->params.roi.height = STV_IMAGE_QCIF_ROWS; + cam->vw.width = STV_IMAGE_QCIF_COLS; + cam->vw.height = STV_IMAGE_QCIF_ROWS; + break; + default: + retval = -EINVAL; + } + return retval; +} + +/****************************************************************************** + * + * configure_sensor + * + *****************************************************************************/ +static int configure_sensor(struct camera_data *cam, + int req_width, int req_height) +{ + int retval; + + switch (cam->params.version.sensor_flags) { + case CPIA2_VP_SENSOR_FLAGS_404: + case CPIA2_VP_SENSOR_FLAGS_407: + case CPIA2_VP_SENSOR_FLAGS_409: + case CPIA2_VP_SENSOR_FLAGS_410: + retval = config_sensor_410(cam, req_width, req_height); + break; + case CPIA2_VP_SENSOR_FLAGS_500: + retval = config_sensor_500(cam, req_width, req_height); + break; + default: + return -EINVAL; + } + + return retval; +} + +/****************************************************************************** + * + * config_sensor_410 + * + *****************************************************************************/ +static int config_sensor_410(struct camera_data *cam, + int req_width, int req_height) +{ + struct cpia2_command cmd; + int i = 0; + int image_size; + int image_type; + int width = req_width; + int height = req_height; + + /*** + * Make sure size doesn't exceed CIF. + ***/ + if (width > STV_IMAGE_CIF_COLS) + width = STV_IMAGE_CIF_COLS; + if (height > STV_IMAGE_CIF_ROWS) + height = STV_IMAGE_CIF_ROWS; + + image_size = cpia2_match_video_size(width, height); + + DBG("Config 410: width = %d, height = %d\n", width, height); + DBG("Image size returned is %d\n", image_size); + if (image_size >= 0) { + set_vw_size(cam, image_size); + width = cam->params.roi.width; + height = cam->params.roi.height; + + DBG("After set_vw_size(), width = %d, height = %d\n", + width, height); + if (width <= 176 && height <= 144) { + DBG("image type = VIDEOSIZE_QCIF\n"); + image_type = VIDEOSIZE_QCIF; + } + else if (width <= 320 && height <= 240) { + DBG("image type = VIDEOSIZE_QVGA\n"); + image_type = VIDEOSIZE_QVGA; + } + else { + DBG("image type = VIDEOSIZE_CIF\n"); + image_type = VIDEOSIZE_CIF; + } + } else { + ERR("ConfigSensor410 failed\n"); + return -EINVAL; + } + + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.direction = TRANSFER_WRITE; + + /* VC Format */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT; + if (image_type == VIDEOSIZE_CIF) { + cmd.buffer.registers[i++].value = + (u8) (CPIA2_VC_VC_FORMAT_UFIRST | + CPIA2_VC_VC_FORMAT_SHORTLINE); + } else { + cmd.buffer.registers[i++].value = + (u8) CPIA2_VC_VC_FORMAT_UFIRST; + } + + /* VC Clocks */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS; + if (image_type == VIDEOSIZE_QCIF) { + if (cam->params.pnp_id.device_type == DEVICE_STV_672) { + cmd.buffer.registers[i++].value= + (u8)(CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 | + CPIA2_VC_VC_672_CLOCKS_SCALING | + CPIA2_VC_VC_CLOCKS_LOGDIV2); + DBG("VC_Clocks (0xc4) should be B\n"); + } + else { + cmd.buffer.registers[i++].value= + (u8)(CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 | + CPIA2_VC_VC_CLOCKS_LOGDIV2); + } + } else { + if (cam->params.pnp_id.device_type == DEVICE_STV_672) { + cmd.buffer.registers[i++].value = + (u8) (CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 | + CPIA2_VC_VC_CLOCKS_LOGDIV0); + } + else { + cmd.buffer.registers[i++].value = + (u8) (CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 | + CPIA2_VC_VC_676_CLOCKS_SCALING | + CPIA2_VC_VC_CLOCKS_LOGDIV0); + } + } + DBG("VC_Clocks (0xc4) = 0x%0X\n", cmd.buffer.registers[i-1].value); + + /* Input reqWidth from VC */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = + (u8) (STV_IMAGE_QCIF_COLS / 4); + else + cmd.buffer.registers[i++].value = + (u8) (STV_IMAGE_CIF_COLS / 4); + + /* Timings */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 0; + else + cmd.buffer.registers[i++].value = (u8) 1; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 208; + else + cmd.buffer.registers[i++].value = (u8) 160; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 0; + else + cmd.buffer.registers[i++].value = (u8) 1; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 160; + else + cmd.buffer.registers[i++].value = (u8) 64; + + /* Output Image Size */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE; + cmd.buffer.registers[i++].value = cam->params.roi.width / 4; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE; + cmd.buffer.registers[i++].value = cam->params.roi.height / 4; + + /* Cropping */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2); + else + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2); + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2); + else + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2); + + /* Scaling registers (defaults) */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN; + cmd.buffer.registers[i++].value = (u8) 31; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN; + cmd.buffer.registers[i++].value = (u8) 31; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT; + cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */ + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT; + cmd.buffer.registers[i++].value = (u8) 0x81; /* = 8/1 = 8 (HIBYTE/LOBYTE) */ + + cmd.reg_count = i; + + cpia2_send_command(cam, &cmd); + + return i; +} + + +/****************************************************************************** + * + * config_sensor_500(cam) + * + *****************************************************************************/ +static int config_sensor_500(struct camera_data *cam, + int req_width, int req_height) +{ + struct cpia2_command cmd; + int i = 0; + int image_size = VIDEOSIZE_CIF; + int image_type = VIDEOSIZE_VGA; + int width = req_width; + int height = req_height; + unsigned int device = cam->params.pnp_id.device_type; + + image_size = cpia2_match_video_size(width, height); + + if (width > STV_IMAGE_CIF_COLS || height > STV_IMAGE_CIF_ROWS) + image_type = VIDEOSIZE_VGA; + else if (width > STV_IMAGE_QVGA_COLS || height > STV_IMAGE_QVGA_ROWS) + image_type = VIDEOSIZE_CIF; + else if (width > STV_IMAGE_QCIF_COLS || height > STV_IMAGE_QCIF_ROWS) + image_type = VIDEOSIZE_QVGA; + else + image_type = VIDEOSIZE_QCIF; + + if (image_size >= 0) { + set_vw_size(cam, image_size); + width = cam->params.roi.width; + height = cam->params.roi.height; + } else { + ERR("ConfigSensor500 failed\n"); + return -EINVAL; + } + + DBG("image_size = %d, width = %d, height = %d, type = %d\n", + image_size, width, height, image_type); + + cmd.req_mode = CAMERAACCESS_TYPE_RANDOM | CAMERAACCESS_VC; + cmd.direction = TRANSFER_WRITE; + i = 0; + + /* VC Format */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_FORMAT; + cmd.buffer.registers[i].value = (u8) CPIA2_VC_VC_FORMAT_UFIRST; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i].value |= (u8) CPIA2_VC_VC_FORMAT_DECIMATING; + i++; + + /* VC Clocks */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_CLOCKS; + if (device == DEVICE_STV_672) { + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i].value = + (u8)CPIA2_VC_VC_CLOCKS_LOGDIV1; + else + cmd.buffer.registers[i].value = + (u8)(CPIA2_VC_VC_672_CLOCKS_SCALING | + CPIA2_VC_VC_CLOCKS_LOGDIV3); + } else { + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i].value = + (u8)CPIA2_VC_VC_CLOCKS_LOGDIV0; + else + cmd.buffer.registers[i].value = + (u8)(CPIA2_VC_VC_676_CLOCKS_SCALING | + CPIA2_VC_VC_CLOCKS_LOGDIV2); + } + i++; + + DBG("VC_CLOCKS = 0x%X\n", cmd.buffer.registers[i-1].value); + + /* Input width from VP */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_IHSIZE_LO; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i].value = + (u8) (STV_IMAGE_VGA_COLS / 4); + else + cmd.buffer.registers[i].value = + (u8) (STV_IMAGE_QVGA_COLS / 4); + i++; + DBG("Input width = %d\n", cmd.buffer.registers[i-1].value); + + /* Timings */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_HI; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = (u8) 2; + else + cmd.buffer.registers[i++].value = (u8) 1; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_XLIM_LO; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = (u8) 250; + else if (image_type == VIDEOSIZE_QVGA) + cmd.buffer.registers[i++].value = (u8) 125; + else + cmd.buffer.registers[i++].value = (u8) 160; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_HI; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = (u8) 2; + else + cmd.buffer.registers[i++].value = (u8) 1; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_YLIM_LO; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = (u8) 12; + else if (image_type == VIDEOSIZE_QVGA) + cmd.buffer.registers[i++].value = (u8) 64; + else + cmd.buffer.registers[i++].value = (u8) 6; + + /* Output Image Size */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_OHSIZE; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = STV_IMAGE_CIF_COLS / 4; + else + cmd.buffer.registers[i++].value = width / 4; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_OVSIZE; + if (image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = STV_IMAGE_CIF_ROWS / 4; + else + cmd.buffer.registers[i++].value = height / 4; + + /* Cropping */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_HCROP; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_VGA_COLS / 4) - (width / 4)) / 2); + else if (image_type == VIDEOSIZE_QVGA) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QVGA_COLS / 4) - (width / 4)) / 2); + else if (image_type == VIDEOSIZE_CIF) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_CIF_COLS / 4) - (width / 4)) / 2); + else /*if (image_type == VIDEOSIZE_QCIF)*/ + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QCIF_COLS / 4) - (width / 4)) / 2); + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VCROP; + if (image_type == VIDEOSIZE_VGA) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_VGA_ROWS / 4) - (height / 4)) / 2); + else if (image_type == VIDEOSIZE_QVGA) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QVGA_ROWS / 4) - (height / 4)) / 2); + else if (image_type == VIDEOSIZE_CIF) + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_CIF_ROWS / 4) - (height / 4)) / 2); + else /*if (image_type == VIDEOSIZE_QCIF)*/ + cmd.buffer.registers[i++].value = + (u8) (((STV_IMAGE_QCIF_ROWS / 4) - (height / 4)) / 2); + + /* Scaling registers (defaults) */ + cmd.buffer.registers[i].index = CPIA2_VC_VC_HPHASE; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 36; + else + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VPHASE; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 32; + else + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HISPAN; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 26; + else + cmd.buffer.registers[i++].value = (u8) 31; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VISPAN; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 21; + else + cmd.buffer.registers[i++].value = (u8) 31; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HICROP; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VICROP; + cmd.buffer.registers[i++].value = (u8) 0; + + cmd.buffer.registers[i].index = CPIA2_VC_VC_HFRACT; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 0x2B; /* 2/11 */ + else + cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */ + + cmd.buffer.registers[i].index = CPIA2_VC_VC_VFRACT; + if (image_type == VIDEOSIZE_CIF || image_type == VIDEOSIZE_QCIF) + cmd.buffer.registers[i++].value = (u8) 0x13; /* 1/3 */ + else + cmd.buffer.registers[i++].value = (u8) 0x81; /* 8/1 */ + + cmd.reg_count = i; + + cpia2_send_command(cam, &cmd); + + return i; +} + + +/****************************************************************************** + * + * setallproperties + * + * This sets all user changeable properties to the values in cam->params. + *****************************************************************************/ +int set_all_properties(struct camera_data *cam) +{ + /** + * Don't set target_kb here, it will be set later. + * framerate and user_mode were already set (set_default_user_mode). + **/ + + cpia2_set_color_params(cam); + + cpia2_usb_change_streaming_alternate(cam, + cam->params.camera_state.stream_mode); + + cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, + cam->params.vp_params.user_effects); + + cpia2_set_flicker_mode(cam, + cam->params.flicker_control.flicker_mode_req); + + cpia2_do_command(cam, + CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, + TRANSFER_WRITE, cam->params.vp_params.gpio_direction); + cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, TRANSFER_WRITE, + cam->params.vp_params.gpio_data); + + wake_system(cam); + + set_lowlight_boost(cam); + + return 0; +} + +/****************************************************************************** + * + * cpia2_save_camera_state + * + *****************************************************************************/ +void cpia2_save_camera_state(struct camera_data *cam) +{ + get_color_params(cam); + cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DIRECTION, TRANSFER_READ, + 0); + cpia2_do_command(cam, CPIA2_CMD_GET_VC_MP_GPIO_DATA, TRANSFER_READ, 0); + /* Don't get framerate or target_kb. Trust the values we already have */ +} + +/****************************************************************************** + * + * get_color_params + * + *****************************************************************************/ +void get_color_params(struct camera_data *cam) +{ + cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0); + cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, TRANSFER_READ, 0); +} + +/****************************************************************************** + * + * cpia2_set_color_params + * + *****************************************************************************/ +void cpia2_set_color_params(struct camera_data *cam) +{ + DBG("Setting color params\n"); + cpia2_set_brightness(cam, cam->params.color_params.brightness); + cpia2_set_contrast(cam, cam->params.color_params.contrast); + cpia2_set_saturation(cam, cam->params.color_params.saturation); +} + +/****************************************************************************** + * + * cpia2_set_flicker_mode + * + *****************************************************************************/ +int cpia2_set_flicker_mode(struct camera_data *cam, int mode) +{ + unsigned char cam_reg; + int err = 0; + + if(cam->params.pnp_id.device_type != DEVICE_STV_672) + return -EINVAL; + + /* Set the appropriate bits in FLICKER_MODES, preserving the rest */ + if((err = cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES, + TRANSFER_READ, 0))) + return err; + cam_reg = cam->params.flicker_control.cam_register; + + switch(mode) { + case NEVER_FLICKER: + cam_reg |= CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; + cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ; + break; + case FLICKER_60: + cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; + cam_reg &= ~CPIA2_VP_FLICKER_MODES_50HZ; + break; + case FLICKER_50: + cam_reg &= ~CPIA2_VP_FLICKER_MODES_NEVER_FLICKER; + cam_reg |= CPIA2_VP_FLICKER_MODES_50HZ; + break; + default: + return -EINVAL; + } + + if((err = cpia2_do_command(cam, CPIA2_CMD_SET_FLICKER_MODES, + TRANSFER_WRITE, cam_reg))) + return err; + + /* Set the appropriate bits in EXP_MODES, preserving the rest */ + if((err = cpia2_do_command(cam, CPIA2_CMD_GET_VP_EXP_MODES, + TRANSFER_READ, 0))) + return err; + cam_reg = cam->params.vp_params.exposure_modes; + + if (mode == NEVER_FLICKER) { + cam_reg |= CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER; + } else { + cam_reg &= ~CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER; + } + + if((err = cpia2_do_command(cam, CPIA2_CMD_SET_VP_EXP_MODES, + TRANSFER_WRITE, cam_reg))) + return err; + + if((err = cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, + TRANSFER_WRITE, 1))) + return err; + + switch(mode) { + case NEVER_FLICKER: + cam->params.flicker_control.flicker_mode_req = mode; + break; + case FLICKER_60: + cam->params.flicker_control.flicker_mode_req = mode; + cam->params.flicker_control.mains_frequency = 60; + break; + case FLICKER_50: + cam->params.flicker_control.flicker_mode_req = mode; + cam->params.flicker_control.mains_frequency = 50; + break; + default: + err = -EINVAL; + } + + return err; +} + +/****************************************************************************** + * + * cpia2_set_property_flip + * + *****************************************************************************/ +void cpia2_set_property_flip(struct camera_data *cam, int prop_val) +{ + unsigned char cam_reg; + + cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); + cam_reg = cam->params.vp_params.user_effects; + + if (prop_val) + { + cam_reg |= CPIA2_VP_USER_EFFECTS_FLIP; + } + else + { + cam_reg &= ~CPIA2_VP_USER_EFFECTS_FLIP; + } + cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, + cam_reg); +} + +/****************************************************************************** + * + * cpia2_set_property_mirror + * + *****************************************************************************/ +void cpia2_set_property_mirror(struct camera_data *cam, int prop_val) +{ + unsigned char cam_reg; + + cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, TRANSFER_READ, 0); + cam_reg = cam->params.vp_params.user_effects; + + if (prop_val) + { + cam_reg |= CPIA2_VP_USER_EFFECTS_MIRROR; + } + else + { + cam_reg &= ~CPIA2_VP_USER_EFFECTS_MIRROR; + } + cpia2_do_command(cam, CPIA2_CMD_SET_USER_EFFECTS, TRANSFER_WRITE, + cam_reg); +} + +/****************************************************************************** + * + * set_target_kb + * + * The new Target KB is set in cam->params.vc_params.target_kb and + * activates on reset. + *****************************************************************************/ + +int cpia2_set_target_kb(struct camera_data *cam, unsigned char value) +{ + DBG("Requested target_kb = %d\n", value); + if (value != cam->params.vc_params.target_kb) { + + cpia2_usb_stream_pause(cam); + + /* reset camera for new target_kb */ + cam->params.vc_params.target_kb = value; + cpia2_reset_camera(cam); + + cpia2_usb_stream_resume(cam); + } + + return 0; +} + +/****************************************************************************** + * + * cpia2_set_gpio + * + *****************************************************************************/ +int cpia2_set_gpio(struct camera_data *cam, unsigned char setting) +{ + int ret; + + /* Set the microport direction (register 0x90, should be defined + * already) to 1 (user output), and set the microport data (0x91) to + * the value in the ioctl argument. + */ + + ret = cpia2_do_command(cam, + CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, + CPIA2_VC_MP_DIR_OUTPUT, + 255); + if (ret < 0) + return ret; + cam->params.vp_params.gpio_direction = 255; + + ret = cpia2_do_command(cam, + CPIA2_CMD_SET_VC_MP_GPIO_DATA, + CPIA2_VC_MP_DIR_OUTPUT, + setting); + if (ret < 0) + return ret; + cam->params.vp_params.gpio_data = setting; + + return 0; +} + +/****************************************************************************** + * + * cpia2_set_fps + * + *****************************************************************************/ +int cpia2_set_fps(struct camera_data *cam, int framerate) +{ + int retval; + + switch(framerate) { + case CPIA2_VP_FRAMERATE_30: + case CPIA2_VP_FRAMERATE_25: + if(cam->params.pnp_id.device_type == DEVICE_STV_672 && + cam->params.version.sensor_flags == + CPIA2_VP_SENSOR_FLAGS_500) { + return -EINVAL; + } + /* Fall through */ + case CPIA2_VP_FRAMERATE_15: + case CPIA2_VP_FRAMERATE_12_5: + case CPIA2_VP_FRAMERATE_7_5: + case CPIA2_VP_FRAMERATE_6_25: + break; + default: + return -EINVAL; + } + + if (cam->params.pnp_id.device_type == DEVICE_STV_672 && + framerate == CPIA2_VP_FRAMERATE_15) + framerate = 0; /* Work around bug in VP4 */ + + retval = cpia2_do_command(cam, + CPIA2_CMD_FRAMERATE_REQ, + TRANSFER_WRITE, + framerate); + + if(retval == 0) + cam->params.vp_params.frame_rate = framerate; + + return retval; +} + +/****************************************************************************** + * + * cpia2_set_brightness + * + *****************************************************************************/ +void cpia2_set_brightness(struct camera_data *cam, unsigned char value) +{ + /*** + * Don't let the register be set to zero - bug in VP4 - flash of full + * brightness + ***/ + if (cam->params.pnp_id.device_type == DEVICE_STV_672 && value == 0) + value++; + DBG("Setting brightness to %d (0x%0x)\n", value, value); + cpia2_do_command(cam,CPIA2_CMD_SET_VP_BRIGHTNESS, TRANSFER_WRITE,value); +} + +/****************************************************************************** + * + * cpia2_set_contrast + * + *****************************************************************************/ +void cpia2_set_contrast(struct camera_data *cam, unsigned char value) +{ + DBG("Setting contrast to %d (0x%0x)\n", value, value); + cam->params.color_params.contrast = value; + cpia2_do_command(cam, CPIA2_CMD_SET_CONTRAST, TRANSFER_WRITE, value); +} + +/****************************************************************************** + * + * cpia2_set_saturation + * + *****************************************************************************/ +void cpia2_set_saturation(struct camera_data *cam, unsigned char value) +{ + DBG("Setting saturation to %d (0x%0x)\n", value, value); + cam->params.color_params.saturation = value; + cpia2_do_command(cam,CPIA2_CMD_SET_VP_SATURATION, TRANSFER_WRITE,value); +} + +/****************************************************************************** + * + * wake_system + * + *****************************************************************************/ +void wake_system(struct camera_data *cam) +{ + cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0); +} + +/****************************************************************************** + * + * set_lowlight_boost + * + * Valid for STV500 sensor only + *****************************************************************************/ +void set_lowlight_boost(struct camera_data *cam) +{ + struct cpia2_command cmd; + + if (cam->params.pnp_id.device_type != DEVICE_STV_672 || + cam->params.version.sensor_flags != CPIA2_VP_SENSOR_FLAGS_500) + return; + + cmd.direction = TRANSFER_WRITE; + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 3; + cmd.start = CPIA2_VP_RAM_ADDR_H; + + cmd.buffer.block_data[0] = 0; /* High byte of address to write to */ + cmd.buffer.block_data[1] = 0x59; /* Low byte of address to write to */ + cmd.buffer.block_data[2] = 0; /* High byte of data to write */ + + cpia2_send_command(cam, &cmd); + + if (cam->params.vp_params.lowlight_boost) { + cmd.buffer.block_data[0] = 0x02; /* Low byte data to write */ + } else { + cmd.buffer.block_data[0] = 0x06; + } + cmd.start = CPIA2_VP_RAM_DATA; + cmd.reg_count = 1; + cpia2_send_command(cam, &cmd); + + /* Rehash the VP4 values */ + cpia2_do_command(cam, CPIA2_CMD_REHASH_VP4, TRANSFER_WRITE, 1); +} + +/****************************************************************************** + * + * cpia2_set_format + * + * Assumes that new size is already set in param struct. + *****************************************************************************/ +void cpia2_set_format(struct camera_data *cam) +{ + cam->flush = true; + + cpia2_usb_stream_pause(cam); + + /* reset camera to new size */ + cpia2_set_low_power(cam); + cpia2_reset_camera(cam); + cam->flush = false; + + cpia2_dbg_dump_registers(cam); + + cpia2_usb_stream_resume(cam); +} + +/****************************************************************************** + * + * cpia2_dbg_dump_registers + * + *****************************************************************************/ +void cpia2_dbg_dump_registers(struct camera_data *cam) +{ +#ifdef _CPIA2_DEBUG_ + struct cpia2_command cmd; + + if (!(debugs_on & DEBUG_DUMP_REGS)) + return; + + cmd.direction = TRANSFER_READ; + + /* Start with bank 0 (SYSTEM) */ + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_SYSTEM; + cmd.reg_count = 3; + cmd.start = 0; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "System Device Hi = 0x%X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "System Device Lo = 0x%X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "System_system control = 0x%X\n", + cmd.buffer.block_data[2]); + + /* Bank 1 (VC) */ + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.reg_count = 4; + cmd.start = 0x80; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "ASIC_ID = 0x%X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "ASIC_REV = 0x%X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "PW_CONTRL = 0x%X\n", + cmd.buffer.block_data[2]); + printk(KERN_DEBUG "WAKEUP = 0x%X\n", + cmd.buffer.block_data[3]); + + cmd.start = 0xA0; /* ST_CTRL */ + cmd.reg_count = 1; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "Stream ctrl = 0x%X\n", + cmd.buffer.block_data[0]); + + cmd.start = 0xA4; /* Stream status */ + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "Stream status = 0x%X\n", + cmd.buffer.block_data[0]); + + cmd.start = 0xA8; /* USB status */ + cmd.reg_count = 3; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "USB_CTRL = 0x%X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "USB_STRM = 0x%X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "USB_STATUS = 0x%X\n", + cmd.buffer.block_data[2]); + + cmd.start = 0xAF; /* USB settings */ + cmd.reg_count = 1; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "USB settings = 0x%X\n", + cmd.buffer.block_data[0]); + + cmd.start = 0xC0; /* VC stuff */ + cmd.reg_count = 26; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VC Control = 0x%0X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "VC Format = 0x%0X\n", + cmd.buffer.block_data[3]); + printk(KERN_DEBUG "VC Clocks = 0x%0X\n", + cmd.buffer.block_data[4]); + printk(KERN_DEBUG "VC IHSize = 0x%0X\n", + cmd.buffer.block_data[5]); + printk(KERN_DEBUG "VC Xlim Hi = 0x%0X\n", + cmd.buffer.block_data[6]); + printk(KERN_DEBUG "VC XLim Lo = 0x%0X\n", + cmd.buffer.block_data[7]); + printk(KERN_DEBUG "VC YLim Hi = 0x%0X\n", + cmd.buffer.block_data[8]); + printk(KERN_DEBUG "VC YLim Lo = 0x%0X\n", + cmd.buffer.block_data[9]); + printk(KERN_DEBUG "VC OHSize = 0x%0X\n", + cmd.buffer.block_data[10]); + printk(KERN_DEBUG "VC OVSize = 0x%0X\n", + cmd.buffer.block_data[11]); + printk(KERN_DEBUG "VC HCrop = 0x%0X\n", + cmd.buffer.block_data[12]); + printk(KERN_DEBUG "VC VCrop = 0x%0X\n", + cmd.buffer.block_data[13]); + printk(KERN_DEBUG "VC HPhase = 0x%0X\n", + cmd.buffer.block_data[14]); + printk(KERN_DEBUG "VC VPhase = 0x%0X\n", + cmd.buffer.block_data[15]); + printk(KERN_DEBUG "VC HIspan = 0x%0X\n", + cmd.buffer.block_data[16]); + printk(KERN_DEBUG "VC VIspan = 0x%0X\n", + cmd.buffer.block_data[17]); + printk(KERN_DEBUG "VC HiCrop = 0x%0X\n", + cmd.buffer.block_data[18]); + printk(KERN_DEBUG "VC ViCrop = 0x%0X\n", + cmd.buffer.block_data[19]); + printk(KERN_DEBUG "VC HiFract = 0x%0X\n", + cmd.buffer.block_data[20]); + printk(KERN_DEBUG "VC ViFract = 0x%0X\n", + cmd.buffer.block_data[21]); + printk(KERN_DEBUG "VC JPeg Opt = 0x%0X\n", + cmd.buffer.block_data[22]); + printk(KERN_DEBUG "VC Creep Per = 0x%0X\n", + cmd.buffer.block_data[23]); + printk(KERN_DEBUG "VC User Sq. = 0x%0X\n", + cmd.buffer.block_data[24]); + printk(KERN_DEBUG "VC Target KB = 0x%0X\n", + cmd.buffer.block_data[25]); + + /*** VP ***/ + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VP; + cmd.reg_count = 14; + cmd.start = 0; + cpia2_send_command(cam, &cmd); + + printk(KERN_DEBUG "VP Dev Hi = 0x%0X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "VP Dev Lo = 0x%0X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "VP Sys State = 0x%0X\n", + cmd.buffer.block_data[2]); + printk(KERN_DEBUG "VP Sys Ctrl = 0x%0X\n", + cmd.buffer.block_data[3]); + printk(KERN_DEBUG "VP Sensor flg = 0x%0X\n", + cmd.buffer.block_data[5]); + printk(KERN_DEBUG "VP Sensor Rev = 0x%0X\n", + cmd.buffer.block_data[6]); + printk(KERN_DEBUG "VP Dev Config = 0x%0X\n", + cmd.buffer.block_data[7]); + printk(KERN_DEBUG "VP GPIO_DIR = 0x%0X\n", + cmd.buffer.block_data[8]); + printk(KERN_DEBUG "VP GPIO_DATA = 0x%0X\n", + cmd.buffer.block_data[9]); + printk(KERN_DEBUG "VP Ram ADDR H = 0x%0X\n", + cmd.buffer.block_data[10]); + printk(KERN_DEBUG "VP Ram ADDR L = 0x%0X\n", + cmd.buffer.block_data[11]); + printk(KERN_DEBUG "VP RAM Data = 0x%0X\n", + cmd.buffer.block_data[12]); + printk(KERN_DEBUG "Do Call = 0x%0X\n", + cmd.buffer.block_data[13]); + + if (cam->params.pnp_id.device_type == DEVICE_STV_672) { + cmd.reg_count = 9; + cmd.start = 0x0E; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n", + cmd.buffer.block_data[2]); + printk(KERN_DEBUG "VP Framerate = 0x%0X\n", + cmd.buffer.block_data[3]); + printk(KERN_DEBUG "VP UserEffect = 0x%0X\n", + cmd.buffer.block_data[4]); + printk(KERN_DEBUG "VP White Bal = 0x%0X\n", + cmd.buffer.block_data[5]); + printk(KERN_DEBUG "VP WB thresh = 0x%0X\n", + cmd.buffer.block_data[6]); + printk(KERN_DEBUG "VP Exp Modes = 0x%0X\n", + cmd.buffer.block_data[7]); + printk(KERN_DEBUG "VP Exp Target = 0x%0X\n", + cmd.buffer.block_data[8]); + + cmd.reg_count = 1; + cmd.start = 0x1B; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VP FlickerMds = 0x%0X\n", + cmd.buffer.block_data[0]); + } else { + cmd.reg_count = 8 ; + cmd.start = 0x0E; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VP Clock Ctrl = 0x%0X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "VP Patch Rev = 0x%0X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "VP Vid Mode = 0x%0X\n", + cmd.buffer.block_data[5]); + printk(KERN_DEBUG "VP Framerate = 0x%0X\n", + cmd.buffer.block_data[6]); + printk(KERN_DEBUG "VP UserEffect = 0x%0X\n", + cmd.buffer.block_data[7]); + + cmd.reg_count = 1; + cmd.start = CPIA2_VP5_EXPOSURE_TARGET; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VP5 Exp Target= 0x%0X\n", + cmd.buffer.block_data[0]); + + cmd.reg_count = 4; + cmd.start = 0x3A; + cpia2_send_command(cam, &cmd); + printk(KERN_DEBUG "VP5 MY Black = 0x%0X\n", + cmd.buffer.block_data[0]); + printk(KERN_DEBUG "VP5 MCY Range = 0x%0X\n", + cmd.buffer.block_data[1]); + printk(KERN_DEBUG "VP5 MYCEILING = 0x%0X\n", + cmd.buffer.block_data[2]); + printk(KERN_DEBUG "VP5 MCUV Sat = 0x%0X\n", + cmd.buffer.block_data[3]); + } +#endif +} + +/****************************************************************************** + * + * reset_camera_struct + * + * Sets all values to the defaults + *****************************************************************************/ +void reset_camera_struct(struct camera_data *cam) +{ + /*** + * The following parameter values are the defaults from the register map. + ***/ + cam->params.color_params.brightness = DEFAULT_BRIGHTNESS; + cam->params.color_params.contrast = DEFAULT_CONTRAST; + cam->params.color_params.saturation = DEFAULT_SATURATION; + cam->params.vp_params.lowlight_boost = 0; + + /* FlickerModes */ + cam->params.flicker_control.flicker_mode_req = NEVER_FLICKER; + cam->params.flicker_control.mains_frequency = 60; + + /* jpeg params */ + cam->params.compression.jpeg_options = CPIA2_VC_VC_JPEG_OPT_DEFAULT; + cam->params.compression.creep_period = 2; + cam->params.compression.user_squeeze = 20; + cam->params.compression.inhibit_htables = false; + + /* gpio params */ + cam->params.vp_params.gpio_direction = 0; /* write, the default safe mode */ + cam->params.vp_params.gpio_data = 0; + + /* Target kb params */ + cam->params.vc_params.target_kb = DEFAULT_TARGET_KB; + + /*** + * Set Sensor FPS as fast as possible. + ***/ + if(cam->params.pnp_id.device_type == DEVICE_STV_672) { + if(cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) + cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_15; + else + cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30; + } else { + cam->params.vp_params.frame_rate = CPIA2_VP_FRAMERATE_30; + } + + /*** + * Set default video mode as large as possible : + * for vga sensor set to vga, for cif sensor set to CIF. + ***/ + if (cam->params.version.sensor_flags == CPIA2_VP_SENSOR_FLAGS_500) { + cam->sensor_type = CPIA2_SENSOR_500; + cam->video_size = VIDEOSIZE_VGA; + cam->params.roi.width = STV_IMAGE_VGA_COLS; + cam->params.roi.height = STV_IMAGE_VGA_ROWS; + } else { + cam->sensor_type = CPIA2_SENSOR_410; + cam->video_size = VIDEOSIZE_CIF; + cam->params.roi.width = STV_IMAGE_CIF_COLS; + cam->params.roi.height = STV_IMAGE_CIF_ROWS; + } + + /*** + * Fill in the v4l structures. video_cap is filled in inside the VIDIOCCAP + * Ioctl. Here, just do the window and picture stucts. + ***/ + cam->vp.palette = (u16) VIDEO_PALETTE_RGB24; /* Is this right? */ + cam->vp.brightness = (u16) cam->params.color_params.brightness * 256; + cam->vp.colour = (u16) cam->params.color_params.saturation * 256; + cam->vp.contrast = (u16) cam->params.color_params.contrast * 256; + + cam->vw.x = 0; + cam->vw.y = 0; + cam->vw.width = cam->params.roi.width; + cam->vw.height = cam->params.roi.height; + cam->vw.flags = 0; + cam->vw.clipcount = 0; + + return; +} + +/****************************************************************************** + * + * cpia2_init_camera_struct + * + * Initializes camera struct, does not call reset to fill in defaults. + *****************************************************************************/ +struct camera_data *cpia2_init_camera_struct(void) +{ + struct camera_data *cam; + + cam = kmalloc(sizeof(*cam), GFP_KERNEL); + + if (!cam) { + ERR("couldn't kmalloc cpia2 struct\n"); + return NULL; + } + + /* Default everything to 0 */ + memset(cam, 0, sizeof(struct camera_data)); + + cam->present = 1; + init_MUTEX(&cam->busy_lock); + init_waitqueue_head(&cam->wq_stream); + + return cam; +} + +/****************************************************************************** + * + * cpia2_init_camera + * + * Initializes camera. + *****************************************************************************/ +int cpia2_init_camera(struct camera_data *cam) +{ + DBG("Start\n"); + + cam->mmapped = false; + + /* Get sensor and asic types before reset. */ + cpia2_set_high_power(cam); + cpia2_get_version_info(cam); + if (cam->params.version.asic_id != CPIA2_ASIC_672) { + ERR("Device IO error (asicID has incorrect value of 0x%X\n", + cam->params.version.asic_id); + return -ENODEV; + } + + /* Set GPIO direction and data to a safe state. */ + cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DIRECTION, + TRANSFER_WRITE, 0); + cpia2_do_command(cam, CPIA2_CMD_SET_VC_MP_GPIO_DATA, + TRANSFER_WRITE, 0); + + /* resetting struct requires version info for sensor and asic types */ + reset_camera_struct(cam); + + cpia2_set_low_power(cam); + + DBG("End\n"); + + return 0; +} + +/****************************************************************************** + * + * cpia2_allocate_buffers + * + *****************************************************************************/ +int cpia2_allocate_buffers(struct camera_data *cam) +{ + int i; + + if(!cam->buffers) { + u32 size = cam->num_frames*sizeof(struct framebuf); + cam->buffers = kmalloc(size, GFP_KERNEL); + if(!cam->buffers) { + ERR("couldn't kmalloc frame buffer structures\n"); + return -ENOMEM; + } + } + + if(!cam->frame_buffer) { + cam->frame_buffer = rvmalloc(cam->frame_size*cam->num_frames); + if (!cam->frame_buffer) { + ERR("couldn't vmalloc frame buffer data area\n"); + kfree(cam->buffers); + cam->buffers = NULL; + return -ENOMEM; + } + } + + for(i=0; i<cam->num_frames-1; ++i) { + cam->buffers[i].next = &cam->buffers[i+1]; + cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size; + cam->buffers[i].status = FRAME_EMPTY; + cam->buffers[i].length = 0; + cam->buffers[i].max_length = 0; + cam->buffers[i].num = i; + } + cam->buffers[i].next = cam->buffers; + cam->buffers[i].data = cam->frame_buffer +i*cam->frame_size; + cam->buffers[i].status = FRAME_EMPTY; + cam->buffers[i].length = 0; + cam->buffers[i].max_length = 0; + cam->buffers[i].num = i; + cam->curbuff = cam->buffers; + cam->workbuff = cam->curbuff->next; + DBG("buffers=%p, curbuff=%p, workbuff=%p\n", cam->buffers, cam->curbuff, + cam->workbuff); + return 0; +} + +/****************************************************************************** + * + * cpia2_free_buffers + * + *****************************************************************************/ +void cpia2_free_buffers(struct camera_data *cam) +{ + if(cam->buffers) { + kfree(cam->buffers); + cam->buffers = NULL; + } + if(cam->frame_buffer) { + rvfree(cam->frame_buffer, cam->frame_size*cam->num_frames); + cam->frame_buffer = NULL; + } +} + +/****************************************************************************** + * + * cpia2_read + * + *****************************************************************************/ +long cpia2_read(struct camera_data *cam, + char __user *buf, unsigned long count, int noblock) +{ + struct framebuf *frame; + if (!count) { + return 0; + } + + if (!buf) { + ERR("%s: buffer NULL\n",__FUNCTION__); + return -EINVAL; + } + + if (!cam) { + ERR("%s: Internal error, camera_data NULL!\n",__FUNCTION__); + return -EINVAL; + } + + /* make this _really_ smp and multithread-safe */ + if (down_interruptible(&cam->busy_lock)) + return -ERESTARTSYS; + + if (!cam->present) { + LOG("%s: camera removed\n",__FUNCTION__); + up(&cam->busy_lock); + return 0; /* EOF */ + } + + if(!cam->streaming) { + /* Start streaming */ + cpia2_usb_stream_start(cam, + cam->params.camera_state.stream_mode); + } + + /* Copy cam->curbuff in case it changes while we're processing */ + frame = cam->curbuff; + if (noblock && frame->status != FRAME_READY) { + up(&cam->busy_lock); + return -EAGAIN; + } + + if(frame->status != FRAME_READY) { + up(&cam->busy_lock); + wait_event_interruptible(cam->wq_stream, + !cam->present || + (frame = cam->curbuff)->status == FRAME_READY); + if (signal_pending(current)) + return -ERESTARTSYS; + /* make this _really_ smp and multithread-safe */ + if (down_interruptible(&cam->busy_lock)) { + return -ERESTARTSYS; + } + if(!cam->present) { + up(&cam->busy_lock); + return 0; + } + } + + /* copy data to user space */ + if (frame->length > count) { + up(&cam->busy_lock); + return -EFAULT; + } + if (copy_to_user(buf, frame->data, frame->length)) { + up(&cam->busy_lock); + return -EFAULT; + } + + count = frame->length; + + frame->status = FRAME_EMPTY; + + up(&cam->busy_lock); + return count; +} + +/****************************************************************************** + * + * cpia2_poll + * + *****************************************************************************/ +unsigned int cpia2_poll(struct camera_data *cam, struct file *filp, + poll_table *wait) +{ + unsigned int status=0; + + if(!cam) { + ERR("%s: Internal error, camera_data not found!\n",__FUNCTION__); + return POLLERR; + } + + down(&cam->busy_lock); + + if(!cam->present) { + up(&cam->busy_lock); + return POLLHUP; + } + + if(!cam->streaming) { + /* Start streaming */ + cpia2_usb_stream_start(cam, + cam->params.camera_state.stream_mode); + } + + up(&cam->busy_lock); + poll_wait(filp, &cam->wq_stream, wait); + down(&cam->busy_lock); + + if(!cam->present) + status = POLLHUP; + else if(cam->curbuff->status == FRAME_READY) + status = POLLIN | POLLRDNORM; + + up(&cam->busy_lock); + return status; +} + +/****************************************************************************** + * + * cpia2_remap_buffer + * + *****************************************************************************/ +int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma) +{ + const char *adr = (const char *)vma->vm_start; + unsigned long size = vma->vm_end-vma->vm_start; + unsigned long start_offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long start = (unsigned long) adr; + unsigned long page, pos; + + if (!cam) + return -ENODEV; + + DBG("mmap offset:%ld size:%ld\n", start_offset, size); + + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -ERESTARTSYS; + + if (!cam->present) { + up(&cam->busy_lock); + return -ENODEV; + } + + if (size > cam->frame_size*cam->num_frames || + (start_offset % cam->frame_size) != 0 || + (start_offset+size > cam->frame_size*cam->num_frames)) { + up(&cam->busy_lock); + return -EINVAL; + } + + pos = ((unsigned long) (cam->frame_buffer)) + start_offset; + while (size > 0) { + page = kvirt_to_pa(pos); + if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) { + up(&cam->busy_lock); + return -EAGAIN; + } + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + cam->mmapped = true; + up(&cam->busy_lock); + return 0; +} + diff --git a/drivers/media/video/cpia2/cpia2_registers.h b/drivers/media/video/cpia2/cpia2_registers.h new file mode 100644 index 00000000000..3bbec514a96 --- /dev/null +++ b/drivers/media/video/cpia2/cpia2_registers.h @@ -0,0 +1,476 @@ +/**************************************************************************** + * + * Filename: cpia2registers.h + * + * Copyright 2001, STMicrolectronics, Inc. + * + * Description: + * Definitions for the CPia2 register set + * + * 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 CPIA2_REGISTER_HEADER +#define CPIA2_REGISTER_HEADER + +/*** + * System register set (Bank 0) + ***/ +#define CPIA2_SYSTEM_DEVICE_HI 0x00 +#define CPIA2_SYSTEM_DEVICE_LO 0x01 + +#define CPIA2_SYSTEM_SYSTEM_CONTROL 0x02 +#define CPIA2_SYSTEM_CONTROL_LOW_POWER 0x00 +#define CPIA2_SYSTEM_CONTROL_HIGH_POWER 0x01 +#define CPIA2_SYSTEM_CONTROL_SUSPEND 0x02 +#define CPIA2_SYSTEM_CONTROL_V2W_ERR 0x10 +#define CPIA2_SYSTEM_CONTROL_RB_ERR 0x10 +#define CPIA2_SYSTEM_CONTROL_CLEAR_ERR 0x80 + +#define CPIA2_SYSTEM_INT_PACKET_CTRL 0x04 +#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_SW_XX 0x01 +#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_EOF 0x02 +#define CPIA2_SYSTEM_INT_PACKET_CTRL_ENABLE_INT1 0x04 + +#define CPIA2_SYSTEM_CACHE_CTRL 0x05 +#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_RESET 0x01 +#define CPIA2_SYSTEM_CACHE_CTRL_CACHE_FLUSH 0x02 + +#define CPIA2_SYSTEM_SERIAL_CTRL 0x06 +#define CPIA2_SYSTEM_SERIAL_CTRL_NULL_CMD 0x00 +#define CPIA2_SYSTEM_SERIAL_CTRL_START_CMD 0x01 +#define CPIA2_SYSTEM_SERIAL_CTRL_STOP_CMD 0x02 +#define CPIA2_SYSTEM_SERIAL_CTRL_WRITE_CMD 0x03 +#define CPIA2_SYSTEM_SERIAL_CTRL_READ_ACK_CMD 0x04 +#define CPIA2_SYSTEM_SERIAL_CTRL_READ_NACK_CMD 0x05 + +#define CPIA2_SYSTEM_SERIAL_DATA 0x07 + +#define CPIA2_SYSTEM_VP_SERIAL_ADDR 0x08 + +/*** + * I2C addresses for various devices in CPiA2 + ***/ +#define CPIA2_SYSTEM_VP_SERIAL_ADDR_SENSOR 0x20 +#define CPIA2_SYSTEM_VP_SERIAL_ADDR_VP 0x88 +#define CPIA2_SYSTEM_VP_SERIAL_ADDR_676_VP 0x8A + +#define CPIA2_SYSTEM_SPARE_REG1 0x09 +#define CPIA2_SYSTEM_SPARE_REG2 0x0A +#define CPIA2_SYSTEM_SPARE_REG3 0x0B + +#define CPIA2_SYSTEM_MC_PORT_0 0x0C +#define CPIA2_SYSTEM_MC_PORT_1 0x0D +#define CPIA2_SYSTEM_MC_PORT_2 0x0E +#define CPIA2_SYSTEM_MC_PORT_3 0x0F + +#define CPIA2_SYSTEM_STATUS_PKT 0x20 +#define CPIA2_SYSTEM_STATUS_PKT_END 0x27 + +#define CPIA2_SYSTEM_DESCRIP_VID_HI 0x30 +#define CPIA2_SYSTEM_DESCRIP_VID_LO 0x31 +#define CPIA2_SYSTEM_DESCRIP_PID_HI 0x32 +#define CPIA2_SYSTEM_DESCRIP_PID_LO 0x33 + +#define CPIA2_SYSTEM_FW_VERSION_HI 0x34 +#define CPIA2_SYSTEM_FW_VERSION_LO 0x35 + +#define CPIA2_SYSTEM_CACHE_START_INDEX 0x80 +#define CPIA2_SYSTEM_CACHE_MAX_WRITES 0x10 + +/*** + * VC register set (Bank 1) + ***/ +#define CPIA2_VC_ASIC_ID 0x80 + +#define CPIA2_VC_ASIC_REV 0x81 + +#define CPIA2_VC_PW_CTRL 0x82 +#define CPIA2_VC_PW_CTRL_COLDSTART 0x01 +#define CPIA2_VC_PW_CTRL_CP_CLK_EN 0x02 +#define CPIA2_VC_PW_CTRL_VP_RESET_N 0x04 +#define CPIA2_VC_PW_CTRL_VC_CLK_EN 0x08 +#define CPIA2_VC_PW_CTRL_VC_RESET_N 0x10 +#define CPIA2_VC_PW_CTRL_GOTO_SUSPEND 0x20 +#define CPIA2_VC_PW_CTRL_UDC_SUSPEND 0x40 +#define CPIA2_VC_PW_CTRL_PWR_DOWN 0x80 + +#define CPIA2_VC_WAKEUP 0x83 +#define CPIA2_VC_WAKEUP_SW_ENABLE 0x01 +#define CPIA2_VC_WAKEUP_XX_ENABLE 0x02 +#define CPIA2_VC_WAKEUP_SW_ATWAKEUP 0x04 +#define CPIA2_VC_WAKEUP_XX_ATWAKEUP 0x08 + +#define CPIA2_VC_CLOCK_CTRL 0x84 +#define CPIA2_VC_CLOCK_CTRL_TESTUP72 0x01 + +#define CPIA2_VC_INT_ENABLE 0x88 +#define CPIA2_VC_INT_ENABLE_XX_IE 0x01 +#define CPIA2_VC_INT_ENABLE_SW_IE 0x02 +#define CPIA2_VC_INT_ENABLE_VC_IE 0x04 +#define CPIA2_VC_INT_ENABLE_USBDATA_IE 0x08 +#define CPIA2_VC_INT_ENABLE_USBSETUP_IE 0x10 +#define CPIA2_VC_INT_ENABLE_USBCFG_IE 0x20 + +#define CPIA2_VC_INT_FLAG 0x89 +#define CPIA2_VC_INT_ENABLE_XX_FLAG 0x01 +#define CPIA2_VC_INT_ENABLE_SW_FLAG 0x02 +#define CPIA2_VC_INT_ENABLE_VC_FLAG 0x04 +#define CPIA2_VC_INT_ENABLE_USBDATA_FLAG 0x08 +#define CPIA2_VC_INT_ENABLE_USBSETUP_FLAG 0x10 +#define CPIA2_VC_INT_ENABLE_USBCFG_FLAG 0x20 +#define CPIA2_VC_INT_ENABLE_SET_RESET_BIT 0x80 + +#define CPIA2_VC_INT_STATE 0x8A +#define CPIA2_VC_INT_STATE_XX_STATE 0x01 +#define CPIA2_VC_INT_STATE_SW_STATE 0x02 + +#define CPIA2_VC_MP_DIR 0x90 +#define CPIA2_VC_MP_DIR_INPUT 0x00 +#define CPIA2_VC_MP_DIR_OUTPUT 0x01 + +#define CPIA2_VC_MP_DATA 0x91 + +#define CPIA2_VC_DP_CTRL 0x98 +#define CPIA2_VC_DP_CTRL_MODE_0 0x00 +#define CPIA2_VC_DP_CTRL_MODE_A 0x01 +#define CPIA2_VC_DP_CTRL_MODE_B 0x02 +#define CPIA2_VC_DP_CTRL_MODE_C 0x03 +#define CPIA2_VC_DP_CTRL_FAKE_FST 0x04 + +#define CPIA2_VC_AD_CTRL 0x99 +#define CPIA2_VC_AD_CTRL_SRC_0 0x00 +#define CPIA2_VC_AD_CTRL_SRC_DIGI_A 0x01 +#define CPIA2_VC_AD_CTRL_SRC_REG 0x02 +#define CPIA2_VC_AD_CTRL_DST_USB 0x00 +#define CPIA2_VC_AD_CTRL_DST_REG 0x04 + +#define CPIA2_VC_AD_TEST_IN 0x9B + +#define CPIA2_VC_AD_TEST_OUT 0x9C + +#define CPIA2_VC_AD_STATUS 0x9D +#define CPIA2_VC_AD_STATUS_EMPTY 0x01 +#define CPIA2_VC_AD_STATUS_FULL 0x02 + +#define CPIA2_VC_DP_DATA 0x9E + +#define CPIA2_VC_ST_CTRL 0xA0 +#define CPIA2_VC_ST_CTRL_SRC_VC 0x00 +#define CPIA2_VC_ST_CTRL_SRC_DP 0x01 +#define CPIA2_VC_ST_CTRL_SRC_REG 0x02 + +#define CPIA2_VC_ST_CTRL_RAW_SELECT 0x04 + +#define CPIA2_VC_ST_CTRL_DST_USB 0x00 +#define CPIA2_VC_ST_CTRL_DST_DP 0x08 +#define CPIA2_VC_ST_CTRL_DST_REG 0x10 + +#define CPIA2_VC_ST_CTRL_FIFO_ENABLE 0x20 +#define CPIA2_VC_ST_CTRL_EOF_DETECT 0x40 + +#define CPIA2_VC_ST_TEST 0xA1 +#define CPIA2_VC_ST_TEST_MODE_MANUAL 0x00 +#define CPIA2_VC_ST_TEST_MODE_INCREMENT 0x02 + +#define CPIA2_VC_ST_TEST_AUTO_FILL 0x08 + +#define CPIA2_VC_ST_TEST_REPEAT_FIFO 0x10 + +#define CPIA2_VC_ST_TEST_IN 0xA2 + +#define CPIA2_VC_ST_TEST_OUT 0xA3 + +#define CPIA2_VC_ST_STATUS 0xA4 +#define CPIA2_VC_ST_STATUS_EMPTY 0x01 +#define CPIA2_VC_ST_STATUS_FULL 0x02 + +#define CPIA2_VC_ST_FRAME_DETECT_1 0xA5 + +#define CPIA2_VC_ST_FRAME_DETECT_2 0xA6 + +#define CPIA2_VC_USB_CTRL 0xA8 +#define CPIA2_VC_USB_CTRL_CMD_STALLED 0x01 +#define CPIA2_VC_USB_CTRL_CMD_READY 0x02 +#define CPIA2_VC_USB_CTRL_CMD_STATUS 0x04 +#define CPIA2_VC_USB_CTRL_CMD_STATUS_DIR 0x08 +#define CPIA2_VC_USB_CTRL_CMD_NO_CLASH 0x10 +#define CPIA2_VC_USB_CTRL_CMD_MICRO_ACCESS 0x80 + +#define CPIA2_VC_USB_STRM 0xA9 +#define CPIA2_VC_USB_STRM_ISO_ENABLE 0x01 +#define CPIA2_VC_USB_STRM_BLK_ENABLE 0x02 +#define CPIA2_VC_USB_STRM_INT_ENABLE 0x04 +#define CPIA2_VC_USB_STRM_AUD_ENABLE 0x08 + +#define CPIA2_VC_USB_STATUS 0xAA +#define CPIA2_VC_USB_STATUS_CMD_IN_PROGRESS 0x01 +#define CPIA2_VC_USB_STATUS_CMD_STATUS_STALL 0x02 +#define CPIA2_VC_USB_STATUS_CMD_HANDSHAKE 0x04 +#define CPIA2_VC_USB_STATUS_CMD_OVERRIDE 0x08 +#define CPIA2_VC_USB_STATUS_CMD_FIFO_BUSY 0x10 +#define CPIA2_VC_USB_STATUS_BULK_REPEAT_TXN 0x20 +#define CPIA2_VC_USB_STATUS_CONFIG_DONE 0x40 +#define CPIA2_VC_USB_STATUS_USB_SUSPEND 0x80 + +#define CPIA2_VC_USB_CMDW 0xAB + +#define CPIA2_VC_USB_DATARW 0xAC + +#define CPIA2_VC_USB_INFO 0xAD + +#define CPIA2_VC_USB_CONFIG 0xAE + +#define CPIA2_VC_USB_SETTINGS 0xAF +#define CPIA2_VC_USB_SETTINGS_CONFIG_MASK 0x03 +#define CPIA2_VC_USB_SETTINGS_INTERFACE_MASK 0x0C +#define CPIA2_VC_USB_SETTINGS_ALTERNATE_MASK 0x70 + +#define CPIA2_VC_USB_ISOLIM 0xB0 + +#define CPIA2_VC_USB_ISOFAILS 0xB1 + +#define CPIA2_VC_USB_ISOMAXPKTHI 0xB2 + +#define CPIA2_VC_USB_ISOMAXPKTLO 0xB3 + +#define CPIA2_VC_V2W_CTRL 0xB8 +#define CPIA2_VC_V2W_SELECT 0x01 + +#define CPIA2_VC_V2W_SCL 0xB9 + +#define CPIA2_VC_V2W_SDA 0xBA + +#define CPIA2_VC_VC_CTRL 0xC0 +#define CPIA2_VC_VC_CTRL_RUN 0x01 +#define CPIA2_VC_VC_CTRL_SINGLESHOT 0x02 +#define CPIA2_VC_VC_CTRL_IDLING 0x04 +#define CPIA2_VC_VC_CTRL_INHIBIT_H_TABLES 0x10 +#define CPIA2_VC_VC_CTRL_INHIBIT_Q_TABLES 0x20 +#define CPIA2_VC_VC_CTRL_INHIBIT_PRIVATE 0x40 + +#define CPIA2_VC_VC_RESTART_IVAL_HI 0xC1 + +#define CPIA2_VC_VC_RESTART_IVAL_LO 0xC2 + +#define CPIA2_VC_VC_FORMAT 0xC3 +#define CPIA2_VC_VC_FORMAT_UFIRST 0x01 +#define CPIA2_VC_VC_FORMAT_MONO 0x02 +#define CPIA2_VC_VC_FORMAT_DECIMATING 0x04 +#define CPIA2_VC_VC_FORMAT_SHORTLINE 0x08 +#define CPIA2_VC_VC_FORMAT_SELFTEST 0x10 + +#define CPIA2_VC_VC_CLOCKS 0xC4 +#define CPIA2_VC_VC_CLOCKS_CLKDIV_MASK 0x03 +#define CPIA2_VC_VC_672_CLOCKS_CIF_DIV_BY_3 0x04 +#define CPIA2_VC_VC_672_CLOCKS_SCALING 0x08 +#define CPIA2_VC_VC_CLOCKS_LOGDIV0 0x00 +#define CPIA2_VC_VC_CLOCKS_LOGDIV1 0x01 +#define CPIA2_VC_VC_CLOCKS_LOGDIV2 0x02 +#define CPIA2_VC_VC_CLOCKS_LOGDIV3 0x03 +#define CPIA2_VC_VC_676_CLOCKS_CIF_DIV_BY_3 0x08 +#define CPIA2_VC_VC_676_CLOCKS_SCALING 0x10 + +#define CPIA2_VC_VC_IHSIZE_LO 0xC5 + +#define CPIA2_VC_VC_XLIM_HI 0xC6 + +#define CPIA2_VC_VC_XLIM_LO 0xC7 + +#define CPIA2_VC_VC_YLIM_HI 0xC8 + +#define CPIA2_VC_VC_YLIM_LO 0xC9 + +#define CPIA2_VC_VC_OHSIZE 0xCA + +#define CPIA2_VC_VC_OVSIZE 0xCB + +#define CPIA2_VC_VC_HCROP 0xCC + +#define CPIA2_VC_VC_VCROP 0xCD + +#define CPIA2_VC_VC_HPHASE 0xCE + +#define CPIA2_VC_VC_VPHASE 0xCF + +#define CPIA2_VC_VC_HISPAN 0xD0 + +#define CPIA2_VC_VC_VISPAN 0xD1 + +#define CPIA2_VC_VC_HICROP 0xD2 + +#define CPIA2_VC_VC_VICROP 0xD3 + +#define CPIA2_VC_VC_HFRACT 0xD4 +#define CPIA2_VC_VC_HFRACT_DEN_MASK 0x0F +#define CPIA2_VC_VC_HFRACT_NUM_MASK 0xF0 + +#define CPIA2_VC_VC_VFRACT 0xD5 +#define CPIA2_VC_VC_VFRACT_DEN_MASK 0x0F +#define CPIA2_VC_VC_VFRACT_NUM_MASK 0xF0 + +#define CPIA2_VC_VC_JPEG_OPT 0xD6 +#define CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE 0x01 +#define CPIA2_VC_VC_JPEG_OPT_NO_DC_AUTO_SQUEEZE 0x02 +#define CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE 0x04 +#define CPIA2_VC_VC_JPEG_OPT_DEFAULT (CPIA2_VC_VC_JPEG_OPT_DOUBLE_SQUEEZE|\ + CPIA2_VC_VC_JPEG_OPT_AUTO_SQUEEZE) + + +#define CPIA2_VC_VC_CREEP_PERIOD 0xD7 +#define CPIA2_VC_VC_USER_SQUEEZE 0xD8 +#define CPIA2_VC_VC_TARGET_KB 0xD9 + +#define CPIA2_VC_VC_AUTO_SQUEEZE 0xE6 + + +/*** + * VP register set (Bank 2) + ***/ +#define CPIA2_VP_DEVICEH 0 +#define CPIA2_VP_DEVICEL 1 + +#define CPIA2_VP_SYSTEMSTATE 0x02 +#define CPIA2_VP_SYSTEMSTATE_HK_ALIVE 0x01 + +#define CPIA2_VP_SYSTEMCTRL 0x03 +#define CPIA2_VP_SYSTEMCTRL_REQ_CLEAR_ERROR 0x80 +#define CPIA2_VP_SYSTEMCTRL_POWER_DOWN_PLL 0x20 +#define CPIA2_VP_SYSTEMCTRL_REQ_SUSPEND_STATE 0x10 +#define CPIA2_VP_SYSTEMCTRL_REQ_SERIAL_WAKEUP 0x08 +#define CPIA2_VP_SYSTEMCTRL_REQ_AUTOLOAD 0x04 +#define CPIA2_VP_SYSTEMCTRL_HK_CONTROL 0x02 +#define CPIA2_VP_SYSTEMCTRL_POWER_CONTROL 0x01 + +#define CPIA2_VP_SENSOR_FLAGS 0x05 +#define CPIA2_VP_SENSOR_FLAGS_404 0x01 +#define CPIA2_VP_SENSOR_FLAGS_407 0x02 +#define CPIA2_VP_SENSOR_FLAGS_409 0x04 +#define CPIA2_VP_SENSOR_FLAGS_410 0x08 +#define CPIA2_VP_SENSOR_FLAGS_500 0x10 + +#define CPIA2_VP_SENSOR_REV 0x06 + +#define CPIA2_VP_DEVICE_CONFIG 0x07 +#define CPIA2_VP_DEVICE_CONFIG_SERIAL_BRIDGE 0x01 + +#define CPIA2_VP_GPIO_DIRECTION 0x08 +#define CPIA2_VP_GPIO_READ 0xFF +#define CPIA2_VP_GPIO_WRITE 0x00 + +#define CPIA2_VP_GPIO_DATA 0x09 + +#define CPIA2_VP_RAM_ADDR_H 0x0A +#define CPIA2_VP_RAM_ADDR_L 0x0B +#define CPIA2_VP_RAM_DATA 0x0C + +#define CPIA2_VP_PATCH_REV 0x0F + +#define CPIA2_VP4_USER_MODE 0x10 +#define CPIA2_VP5_USER_MODE 0x13 +#define CPIA2_VP_USER_MODE_CIF 0x01 +#define CPIA2_VP_USER_MODE_QCIFDS 0x02 +#define CPIA2_VP_USER_MODE_QCIFPTC 0x04 +#define CPIA2_VP_USER_MODE_QVGADS 0x08 +#define CPIA2_VP_USER_MODE_QVGAPTC 0x10 +#define CPIA2_VP_USER_MODE_VGA 0x20 + +#define CPIA2_VP4_FRAMERATE_REQUEST 0x11 +#define CPIA2_VP5_FRAMERATE_REQUEST 0x14 +#define CPIA2_VP_FRAMERATE_60 0x80 +#define CPIA2_VP_FRAMERATE_50 0x40 +#define CPIA2_VP_FRAMERATE_30 0x20 +#define CPIA2_VP_FRAMERATE_25 0x10 +#define CPIA2_VP_FRAMERATE_15 0x08 +#define CPIA2_VP_FRAMERATE_12_5 0x04 +#define CPIA2_VP_FRAMERATE_7_5 0x02 +#define CPIA2_VP_FRAMERATE_6_25 0x01 + +#define CPIA2_VP4_USER_EFFECTS 0x12 +#define CPIA2_VP5_USER_EFFECTS 0x15 +#define CPIA2_VP_USER_EFFECTS_COLBARS 0x01 +#define CPIA2_VP_USER_EFFECTS_COLBARS_GRAD 0x02 +#define CPIA2_VP_USER_EFFECTS_MIRROR 0x04 +#define CPIA2_VP_USER_EFFECTS_FLIP 0x40 // VP5 only + +/* NOTE: CPIA2_VP_EXPOSURE_MODES shares the same register as VP5 User + * Effects */ +#define CPIA2_VP_EXPOSURE_MODES 0x15 +#define CPIA2_VP_EXPOSURE_MODES_INHIBIT_FLICKER 0x20 +#define CPIA2_VP_EXPOSURE_MODES_COMPILE_EXP 0x10 + +#define CPIA2_VP4_EXPOSURE_TARGET 0x16 // VP4 +#define CPIA2_VP5_EXPOSURE_TARGET 0x20 // VP5 + +#define CPIA2_VP_FLICKER_MODES 0x1B +#define CPIA2_VP_FLICKER_MODES_50HZ 0x80 +#define CPIA2_VP_FLICKER_MODES_CUSTOM_FLT_FFREQ 0x40 +#define CPIA2_VP_FLICKER_MODES_NEVER_FLICKER 0x20 +#define CPIA2_VP_FLICKER_MODES_INHIBIT_RUB 0x10 +#define CPIA2_VP_FLICKER_MODES_ADJUST_LINE_FREQ 0x08 +#define CPIA2_VP_FLICKER_MODES_CUSTOM_INT_FFREQ 0x04 + +#define CPIA2_VP_UMISC 0x1D +#define CPIA2_VP_UMISC_FORCE_MONO 0x80 +#define CPIA2_VP_UMISC_FORCE_ID_MASK 0x40 +#define CPIA2_VP_UMISC_INHIBIT_AUTO_FGS 0x20 +#define CPIA2_VP_UMISC_INHIBIT_AUTO_DIMS 0x08 +#define CPIA2_VP_UMISC_OPT_FOR_SENSOR_DS 0x04 +#define CPIA2_VP_UMISC_INHIBIT_AUTO_MODE_INT 0x02 + +#define CPIA2_VP5_ANTIFLKRSETUP 0x22 //34 + +#define CPIA2_VP_INTERPOLATION 0x24 +#define CPIA2_VP_INTERPOLATION_EVEN_FIRST 0x40 +#define CPIA2_VP_INTERPOLATION_HJOG 0x20 +#define CPIA2_VP_INTERPOLATION_VJOG 0x10 + +#define CPIA2_VP_GAMMA 0x25 +#define CPIA2_VP_DEFAULT_GAMMA 0x10 + +#define CPIA2_VP_YRANGE 0x26 + +#define CPIA2_VP_SATURATION 0x27 + +#define CPIA2_VP5_MYBLACK_LEVEL 0x3A //58 +#define CPIA2_VP5_MCYRANGE 0x3B //59 +#define CPIA2_VP5_MYCEILING 0x3C //60 +#define CPIA2_VP5_MCUVSATURATION 0x3D //61 + + +#define CPIA2_VP_REHASH_VALUES 0x60 + + +/*** + * Common sensor registers + ***/ +#define CPIA2_SENSOR_DEVICE_H 0x00 +#define CPIA2_SENSOR_DEVICE_L 0x01 + +#define CPIA2_SENSOR_DATA_FORMAT 0x16 +#define CPIA2_SENSOR_DATA_FORMAT_HMIRROR 0x08 +#define CPIA2_SENSOR_DATA_FORMAT_VMIRROR 0x10 + +#define CPIA2_SENSOR_CR1 0x76 +#define CPIA2_SENSOR_CR1_STAND_BY 0x01 +#define CPIA2_SENSOR_CR1_DOWN_RAMP_GEN 0x02 +#define CPIA2_SENSOR_CR1_DOWN_COLUMN_ADC 0x04 +#define CPIA2_SENSOR_CR1_DOWN_CAB_REGULATOR 0x08 +#define CPIA2_SENSOR_CR1_DOWN_AUDIO_REGULATOR 0x10 +#define CPIA2_SENSOR_CR1_DOWN_VRT_AMP 0x20 +#define CPIA2_SENSOR_CR1_DOWN_BAND_GAP 0x40 + +#endif diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c new file mode 100644 index 00000000000..f4da0294149 --- /dev/null +++ b/drivers/media/video/cpia2/cpia2_usb.c @@ -0,0 +1,907 @@ +/**************************************************************************** + * + * Filename: cpia2_usb.c + * + * Copyright 2001, STMicrolectronics, Inc. + * Contact: steve.miller@st.com + * + * Description: + * This is a USB driver for CPia2 based video cameras. + * The infrastructure of this driver is based on the cpia usb driver by + * Jochen Scharrlach and Johannes Erdfeldt. + * + * 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. + * + * Stripped of 2.4 stuff ready for main kernel submit by + * Alan Cox <alan@redhat.com> + ****************************************************************************/ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include "cpia2.h" + +static int frame_sizes[] = { + 0, // USBIF_CMDONLY + 0, // USBIF_BULK + 128, // USBIF_ISO_1 + 384, // USBIF_ISO_2 + 640, // USBIF_ISO_3 + 768, // USBIF_ISO_4 + 896, // USBIF_ISO_5 + 1023, // USBIF_ISO_6 +}; + +#define FRAMES_PER_DESC 10 +#define FRAME_SIZE_PER_DESC frame_sizes[cam->cur_alt] + +static void process_frame(struct camera_data *cam); +static void cpia2_usb_complete(struct urb *urb, struct pt_regs *); +static int cpia2_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id); +static void cpia2_usb_disconnect(struct usb_interface *intf); + +static void free_sbufs(struct camera_data *cam); +static void add_APPn(struct camera_data *cam); +static void add_COM(struct camera_data *cam); +static int submit_urbs(struct camera_data *cam); +static int set_alternate(struct camera_data *cam, unsigned int alt); +static int configure_transfer_mode(struct camera_data *cam, unsigned int alt); + +static struct usb_device_id cpia2_id_table[] = { + {USB_DEVICE(0x0553, 0x0100)}, + {USB_DEVICE(0x0553, 0x0140)}, + {USB_DEVICE(0x0553, 0x0151)}, /* STV0676 */ + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, cpia2_id_table); + +static struct usb_driver cpia2_driver = { + .name = "cpia2", + .probe = cpia2_usb_probe, + .disconnect = cpia2_usb_disconnect, + .id_table = cpia2_id_table +}; + + +/****************************************************************************** + * + * process_frame + * + *****************************************************************************/ +static void process_frame(struct camera_data *cam) +{ + static int frame_count = 0; + + unsigned char *inbuff = cam->workbuff->data; + + DBG("Processing frame #%d, current:%d\n", + cam->workbuff->num, cam->curbuff->num); + + if(cam->workbuff->length > cam->workbuff->max_length) + cam->workbuff->max_length = cam->workbuff->length; + + if ((inbuff[0] == 0xFF) && (inbuff[1] == 0xD8)) { + frame_count++; + } else { + cam->workbuff->status = FRAME_ERROR; + DBG("Start of frame not found\n"); + return; + } + + /*** + * Now the output buffer should have a JPEG image in it. + ***/ + if(!cam->first_image_seen) { + /* Always skip the first image after streaming + * starts. It is almost certainly corrupt. */ + cam->first_image_seen = 1; + cam->workbuff->status = FRAME_EMPTY; + return; + } + if (cam->workbuff->length > 3) { + if(cam->mmapped && + cam->workbuff->length < cam->workbuff->max_length) { + /* No junk in the buffers */ + memset(cam->workbuff->data+cam->workbuff->length, + 0, cam->workbuff->max_length- + cam->workbuff->length); + } + cam->workbuff->max_length = cam->workbuff->length; + cam->workbuff->status = FRAME_READY; + + if(!cam->mmapped && cam->num_frames > 2) { + /* During normal reading, the most recent + * frame will be read. If the current frame + * hasn't started reading yet, it will never + * be read, so mark it empty. If the buffer is + * mmapped, or we have few buffers, we need to + * wait for the user to free the buffer. + * + * NOTE: This is not entirely foolproof with 3 + * buffers, but it would take an EXTREMELY + * overloaded system to cause problems (possible + * image data corruption). Basically, it would + * need to take more time to execute cpia2_read + * than it would for the camera to send + * cam->num_frames-2 frames before problems + * could occur. + */ + cam->curbuff->status = FRAME_EMPTY; + } + cam->curbuff = cam->workbuff; + cam->workbuff = cam->workbuff->next; + DBG("Changed buffers, work:%d, current:%d\n", + cam->workbuff->num, cam->curbuff->num); + return; + } else { + DBG("Not enough data for an image.\n"); + } + + cam->workbuff->status = FRAME_ERROR; + return; +} + +/****************************************************************************** + * + * add_APPn + * + * Adds a user specified APPn record + *****************************************************************************/ +static void add_APPn(struct camera_data *cam) +{ + if(cam->APP_len > 0) { + cam->workbuff->data[cam->workbuff->length++] = 0xFF; + cam->workbuff->data[cam->workbuff->length++] = 0xE0+cam->APPn; + cam->workbuff->data[cam->workbuff->length++] = 0; + cam->workbuff->data[cam->workbuff->length++] = cam->APP_len+2; + memcpy(cam->workbuff->data+cam->workbuff->length, + cam->APP_data, cam->APP_len); + cam->workbuff->length += cam->APP_len; + } +} + +/****************************************************************************** + * + * add_COM + * + * Adds a user specified COM record + *****************************************************************************/ +static void add_COM(struct camera_data *cam) +{ + if(cam->COM_len > 0) { + cam->workbuff->data[cam->workbuff->length++] = 0xFF; + cam->workbuff->data[cam->workbuff->length++] = 0xFE; + cam->workbuff->data[cam->workbuff->length++] = 0; + cam->workbuff->data[cam->workbuff->length++] = cam->COM_len+2; + memcpy(cam->workbuff->data+cam->workbuff->length, + cam->COM_data, cam->COM_len); + cam->workbuff->length += cam->COM_len; + } +} + +/****************************************************************************** + * + * cpia2_usb_complete + * + * callback when incoming packet is received + *****************************************************************************/ +static void cpia2_usb_complete(struct urb *urb, struct pt_regs *regs) +{ + int i; + unsigned char *cdata; + static int frame_ready = false; + struct camera_data *cam = (struct camera_data *) urb->context; + + if (urb->status!=0) { + if (!(urb->status == -ENOENT || + urb->status == -ECONNRESET || + urb->status == -ESHUTDOWN)) + { + DBG("urb->status = %d!\n", urb->status); + } + DBG("Stopping streaming\n"); + return; + } + + if (!cam->streaming || !cam->present || cam->open_count == 0) { + LOG("Will now stop the streaming: streaming = %d, " + "present=%d, open_count=%d\n", + cam->streaming, cam->present, cam->open_count); + return; + } + + /*** + * Packet collater + ***/ + //DBG("Collating %d packets\n", urb->number_of_packets); + for (i = 0; i < urb->number_of_packets; i++) { + u16 checksum, iso_checksum; + int j; + int n = urb->iso_frame_desc[i].actual_length; + int st = urb->iso_frame_desc[i].status; + + if(cam->workbuff->status == FRAME_READY) { + struct framebuf *ptr; + /* Try to find an available buffer */ + DBG("workbuff full, searching\n"); + for (ptr = cam->workbuff->next; + ptr != cam->workbuff; + ptr = ptr->next) + { + if (ptr->status == FRAME_EMPTY) { + ptr->status = FRAME_READING; + ptr->length = 0; + break; + } + } + if (ptr == cam->workbuff) + break; /* No READING or EMPTY buffers left */ + + cam->workbuff = ptr; + } + + if (cam->workbuff->status == FRAME_EMPTY || + cam->workbuff->status == FRAME_ERROR) { + cam->workbuff->status = FRAME_READING; + cam->workbuff->length = 0; + } + + //DBG(" Packet %d length = %d, status = %d\n", i, n, st); + cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + + if (st) { + LOG("cpia2 data error: [%d] len=%d, status = %d\n", + i, n, st); + if(!ALLOW_CORRUPT) + cam->workbuff->status = FRAME_ERROR; + continue; + } + + if(n<=2) + continue; + + checksum = 0; + for(j=0; j<n-2; ++j) + checksum += cdata[j]; + iso_checksum = cdata[j] + cdata[j+1]*256; + if(checksum != iso_checksum) { + LOG("checksum mismatch: [%d] len=%d, calculated = %x, checksum = %x\n", + i, n, (int)checksum, (int)iso_checksum); + if(!ALLOW_CORRUPT) { + cam->workbuff->status = FRAME_ERROR; + continue; + } + } + n -= 2; + + if(cam->workbuff->status != FRAME_READING) { + if((0xFF == cdata[0] && 0xD8 == cdata[1]) || + (0xD8 == cdata[0] && 0xFF == cdata[1] && + 0 != cdata[2])) { + /* frame is skipped, but increment total + * frame count anyway */ + cam->frame_count++; + } + DBG("workbuff not reading, status=%d\n", + cam->workbuff->status); + continue; + } + + if (cam->frame_size < cam->workbuff->length + n) { + ERR("buffer overflow! length: %d, n: %d\n", + cam->workbuff->length, n); + cam->workbuff->status = FRAME_ERROR; + if(cam->workbuff->length > cam->workbuff->max_length) + cam->workbuff->max_length = + cam->workbuff->length; + continue; + } + + if (cam->workbuff->length == 0) { + int data_offset; + if ((0xD8 == cdata[0]) && (0xFF == cdata[1])) { + data_offset = 1; + } else if((0xFF == cdata[0]) && (0xD8 == cdata[1]) + && (0xFF == cdata[2])) { + data_offset = 2; + } else { + DBG("Ignoring packet, not beginning!\n"); + continue; + } + DBG("Start of frame pattern found\n"); + do_gettimeofday(&cam->workbuff->timestamp); + cam->workbuff->seq = cam->frame_count++; + cam->workbuff->data[0] = 0xFF; + cam->workbuff->data[1] = 0xD8; + cam->workbuff->length = 2; + add_APPn(cam); + add_COM(cam); + memcpy(cam->workbuff->data+cam->workbuff->length, + cdata+data_offset, n-data_offset); + cam->workbuff->length += n-data_offset; + } else if (cam->workbuff->length > 0) { + memcpy(cam->workbuff->data + cam->workbuff->length, + cdata, n); + cam->workbuff->length += n; + } + + if ((cam->workbuff->length >= 3) && + (cam->workbuff->data[cam->workbuff->length - 3] == 0xFF) && + (cam->workbuff->data[cam->workbuff->length - 2] == 0xD9) && + (cam->workbuff->data[cam->workbuff->length - 1] == 0xFF)) { + frame_ready = true; + cam->workbuff->data[cam->workbuff->length - 1] = 0; + cam->workbuff->length -= 1; + } else if ((cam->workbuff->length >= 2) && + (cam->workbuff->data[cam->workbuff->length - 2] == 0xFF) && + (cam->workbuff->data[cam->workbuff->length - 1] == 0xD9)) { + frame_ready = true; + } + + if (frame_ready) { + DBG("Workbuff image size = %d\n",cam->workbuff->length); + process_frame(cam); + + frame_ready = false; + + if (waitqueue_active(&cam->wq_stream)) + wake_up_interruptible(&cam->wq_stream); + } + } + + if(cam->streaming) { + /* resubmit */ + urb->dev = cam->dev; + if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0) + ERR("%s: usb_submit_urb ret %d!\n", __func__, i); + } +} + +/****************************************************************************** + * + * configure_transfer_mode + * + *****************************************************************************/ +static int configure_transfer_mode(struct camera_data *cam, unsigned int alt) +{ + static unsigned char iso_regs[8][4] = { + {0x00, 0x00, 0x00, 0x00}, + {0x00, 0x00, 0x00, 0x00}, + {0xB9, 0x00, 0x00, 0x7E}, + {0xB9, 0x00, 0x01, 0x7E}, + {0xB9, 0x00, 0x02, 0x7E}, + {0xB9, 0x00, 0x02, 0xFE}, + {0xB9, 0x00, 0x03, 0x7E}, + {0xB9, 0x00, 0x03, 0xFD} + }; + struct cpia2_command cmd; + unsigned char reg; + + if(!cam->present) + return -ENODEV; + + /*** + * Write the isoc registers according to the alternate selected + ***/ + cmd.direction = TRANSFER_WRITE; + cmd.buffer.block_data[0] = iso_regs[alt][0]; + cmd.buffer.block_data[1] = iso_regs[alt][1]; + cmd.buffer.block_data[2] = iso_regs[alt][2]; + cmd.buffer.block_data[3] = iso_regs[alt][3]; + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.start = CPIA2_VC_USB_ISOLIM; + cmd.reg_count = 4; + cpia2_send_command(cam, &cmd); + + /*** + * Enable relevant streams before starting polling. + * First read USB Stream Config Register. + ***/ + cmd.direction = TRANSFER_READ; + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cmd.start = CPIA2_VC_USB_STRM; + cmd.reg_count = 1; + cpia2_send_command(cam, &cmd); + reg = cmd.buffer.block_data[0]; + + /* Clear iso, bulk, and int */ + reg &= ~(CPIA2_VC_USB_STRM_BLK_ENABLE | + CPIA2_VC_USB_STRM_ISO_ENABLE | + CPIA2_VC_USB_STRM_INT_ENABLE); + + if (alt == USBIF_BULK) { + DBG("Enabling bulk xfer\n"); + reg |= CPIA2_VC_USB_STRM_BLK_ENABLE; /* Enable Bulk */ + cam->xfer_mode = XFER_BULK; + } else if (alt >= USBIF_ISO_1) { + DBG("Enabling ISOC xfer\n"); + reg |= CPIA2_VC_USB_STRM_ISO_ENABLE; + cam->xfer_mode = XFER_ISOC; + } + + cmd.buffer.block_data[0] = reg; + cmd.direction = TRANSFER_WRITE; + cmd.start = CPIA2_VC_USB_STRM; + cmd.reg_count = 1; + cmd.req_mode = CAMERAACCESS_TYPE_BLOCK | CAMERAACCESS_VC; + cpia2_send_command(cam, &cmd); + + return 0; +} + +/****************************************************************************** + * + * cpia2_usb_change_streaming_alternate + * + *****************************************************************************/ +int cpia2_usb_change_streaming_alternate(struct camera_data *cam, + unsigned int alt) +{ + int ret = 0; + + if(alt < USBIF_ISO_1 || alt > USBIF_ISO_6) + return -EINVAL; + + if(alt == cam->params.camera_state.stream_mode) + return 0; + + cpia2_usb_stream_pause(cam); + + configure_transfer_mode(cam, alt); + + cam->params.camera_state.stream_mode = alt; + + /* Reset the camera to prevent image quality degradation */ + cpia2_reset_camera(cam); + + cpia2_usb_stream_resume(cam); + + return ret; +} + +/****************************************************************************** + * + * set_alternate + * + *****************************************************************************/ +int set_alternate(struct camera_data *cam, unsigned int alt) +{ + int ret = 0; + + if(alt == cam->cur_alt) + return 0; + + if (cam->cur_alt != USBIF_CMDONLY) { + DBG("Changing from alt %d to %d\n", cam->cur_alt, USBIF_CMDONLY); + ret = usb_set_interface(cam->dev, cam->iface, USBIF_CMDONLY); + if (ret != 0) + return ret; + } + if (alt != USBIF_CMDONLY) { + DBG("Changing from alt %d to %d\n", USBIF_CMDONLY, alt); + ret = usb_set_interface(cam->dev, cam->iface, alt); + if (ret != 0) + return ret; + } + + cam->old_alt = cam->cur_alt; + cam->cur_alt = alt; + + return ret; +} + +/****************************************************************************** + * + * free_sbufs + * + * Free all cam->sbuf[]. All non-NULL .data and .urb members that are non-NULL + * are assumed to be allocated. Non-NULL .urb members are also assumed to be + * submitted (and must therefore be killed before they are freed). + *****************************************************************************/ +static void free_sbufs(struct camera_data *cam) +{ + int i; + + for (i = 0; i < NUM_SBUF; i++) { + if(cam->sbuf[i].urb) { + usb_kill_urb(cam->sbuf[i].urb); + usb_free_urb(cam->sbuf[i].urb); + cam->sbuf[i].urb = NULL; + } + if(cam->sbuf[i].data) { + kfree(cam->sbuf[i].data); + cam->sbuf[i].data = NULL; + } + } +} + +/******* +* Convenience functions +*******/ +/**************************************************************************** + * + * write_packet + * + ***************************************************************************/ +static int write_packet(struct usb_device *udev, + u8 request, u8 * registers, u16 start, size_t size) +{ + if (!registers || size <= 0) + return -EINVAL; + + return usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + request, + USB_TYPE_VENDOR | USB_RECIP_DEVICE, + start, /* value */ + 0, /* index */ + registers, /* buffer */ + size, + HZ); +} + +/**************************************************************************** + * + * read_packet + * + ***************************************************************************/ +static int read_packet(struct usb_device *udev, + u8 request, u8 * registers, u16 start, size_t size) +{ + if (!registers || size <= 0) + return -EINVAL; + + return usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + request, + USB_DIR_IN|USB_TYPE_VENDOR|USB_RECIP_DEVICE, + start, /* value */ + 0, /* index */ + registers, /* buffer */ + size, + HZ); +} + +/****************************************************************************** + * + * cpia2_usb_transfer_cmd + * + *****************************************************************************/ +int cpia2_usb_transfer_cmd(struct camera_data *cam, + void *registers, + u8 request, u8 start, u8 count, u8 direction) +{ + int err = 0; + struct usb_device *udev = cam->dev; + + if (!udev) { + ERR("%s: Internal driver error: udev is NULL\n", __func__); + return -EINVAL; + } + + if (!registers) { + ERR("%s: Internal driver error: register array is NULL\n", __func__); + return -EINVAL; + } + + if (direction == TRANSFER_READ) { + err = read_packet(udev, request, (u8 *)registers, start, count); + if (err > 0) + err = 0; + } else if (direction == TRANSFER_WRITE) { + err =write_packet(udev, request, (u8 *)registers, start, count); + if (err < 0) { + LOG("Control message failed, err val = %d\n", err); + LOG("Message: request = 0x%0X, start = 0x%0X\n", + request, start); + LOG("Message: count = %d, register[0] = 0x%0X\n", + count, ((unsigned char *) registers)[0]); + } else + err=0; + } else { + LOG("Unexpected first byte of direction: %d\n", + direction); + return -EINVAL; + } + + if(err != 0) + LOG("Unexpected error: %d\n", err); + return err; +} + + +/****************************************************************************** + * + * submit_urbs + * + *****************************************************************************/ +static int submit_urbs(struct camera_data *cam) +{ + struct urb *urb; + int fx, err, i; + + for(i=0; i<NUM_SBUF; ++i) { + if (cam->sbuf[i].data) + continue; + cam->sbuf[i].data = + kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL); + if (!cam->sbuf[i].data) { + return -ENOMEM; + } + } + + /* We double buffer the Isoc lists, and also know the polling + * interval is every frame (1 == (1 << (bInterval -1))). + */ + for(i=0; i<NUM_SBUF; ++i) { + if(cam->sbuf[i].urb) { + continue; + } + urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); + if (!urb) { + return -ENOMEM; + } + + cam->sbuf[i].urb = urb; + urb->dev = cam->dev; + urb->context = cam; + urb->pipe = usb_rcvisocpipe(cam->dev, 1 /*ISOC endpoint*/); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = cam->sbuf[i].data; + urb->complete = cpia2_usb_complete; + urb->number_of_packets = FRAMES_PER_DESC; + urb->interval = 1; + urb->transfer_buffer_length = + FRAME_SIZE_PER_DESC * FRAMES_PER_DESC; + + for (fx = 0; fx < FRAMES_PER_DESC; fx++) { + urb->iso_frame_desc[fx].offset = + FRAME_SIZE_PER_DESC * fx; + urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC; + } + } + + + /* Queue the ISO urbs, and resubmit in the completion handler */ + for(i=0; i<NUM_SBUF; ++i) { + err = usb_submit_urb(cam->sbuf[i].urb, GFP_KERNEL); + if (err) { + ERR("usb_submit_urb[%d]() = %d\n", i, err); + return err; + } + } + + return 0; +} + +/****************************************************************************** + * + * cpia2_usb_stream_start + * + *****************************************************************************/ +int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate) +{ + int ret; + int old_alt; + + if(cam->streaming) + return 0; + + if (cam->flush) { + int i; + DBG("Flushing buffers\n"); + for(i=0; i<cam->num_frames; ++i) { + cam->buffers[i].status = FRAME_EMPTY; + cam->buffers[i].length = 0; + } + cam->curbuff = &cam->buffers[0]; + cam->workbuff = cam->curbuff->next; + cam->flush = false; + } + + old_alt = cam->params.camera_state.stream_mode; + cam->params.camera_state.stream_mode = 0; + ret = cpia2_usb_change_streaming_alternate(cam, alternate); + if (ret < 0) { + int ret2; + ERR("cpia2_usb_change_streaming_alternate() = %d!\n", ret); + cam->params.camera_state.stream_mode = old_alt; + ret2 = set_alternate(cam, USBIF_CMDONLY); + if (ret2 < 0) { + ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already " + "failed. Then tried to call " + "set_alternate(USBIF_CMDONLY) = %d.\n", + alternate, ret, ret2); + } + } else { + cam->frame_count = 0; + cam->streaming = 1; + ret = cpia2_usb_stream_resume(cam); + } + return ret; +} + +/****************************************************************************** + * + * cpia2_usb_stream_pause + * + *****************************************************************************/ +int cpia2_usb_stream_pause(struct camera_data *cam) +{ + int ret = 0; + if(cam->streaming) { + ret = set_alternate(cam, USBIF_CMDONLY); + free_sbufs(cam); + } + return ret; +} + +/****************************************************************************** + * + * cpia2_usb_stream_resume + * + *****************************************************************************/ +int cpia2_usb_stream_resume(struct camera_data *cam) +{ + int ret = 0; + if(cam->streaming) { + cam->first_image_seen = 0; + ret = set_alternate(cam, cam->params.camera_state.stream_mode); + if(ret == 0) { + ret = submit_urbs(cam); + } + } + return ret; +} + +/****************************************************************************** + * + * cpia2_usb_stream_stop + * + *****************************************************************************/ +int cpia2_usb_stream_stop(struct camera_data *cam) +{ + int ret; + ret = cpia2_usb_stream_pause(cam); + cam->streaming = 0; + configure_transfer_mode(cam, 0); + return ret; +} + +/****************************************************************************** + * + * cpia2_usb_probe + * + * Probe and initialize. + *****************************************************************************/ +static int cpia2_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct usb_interface_descriptor *interface; + struct camera_data *cam; + int ret; + + /* A multi-config CPiA2 camera? */ + if (udev->descriptor.bNumConfigurations != 1) + return -ENODEV; + interface = &intf->cur_altsetting->desc; + + /* If we get to this point, we found a CPiA2 camera */ + LOG("CPiA2 USB camera found\n"); + + if((cam = cpia2_init_camera_struct()) == NULL) + return -ENOMEM; + + cam->dev = udev; + cam->iface = interface->bInterfaceNumber; + + ret = set_alternate(cam, USBIF_CMDONLY); + if (ret < 0) { + ERR("%s: usb_set_interface error (ret = %d)\n", __func__, ret); + kfree(cam); + return ret; + } + + if ((ret = cpia2_register_camera(cam)) < 0) { + ERR("%s: Failed to register cpia2 camera (ret = %d)\n", __func__, ret); + kfree(cam); + return ret; + } + + + if((ret = cpia2_init_camera(cam)) < 0) { + ERR("%s: failed to initialize cpia2 camera (ret = %d)\n", __func__, ret); + cpia2_unregister_camera(cam); + kfree(cam); + return ret; + } + LOG(" CPiA Version: %d.%02d (%d.%d)\n", + cam->params.version.firmware_revision_hi, + cam->params.version.firmware_revision_lo, + cam->params.version.asic_id, + cam->params.version.asic_rev); + LOG(" CPiA PnP-ID: %04x:%04x:%04x\n", + cam->params.pnp_id.vendor, + cam->params.pnp_id.product, + cam->params.pnp_id.device_revision); + LOG(" SensorID: %d.(version %d)\n", + cam->params.version.sensor_flags, + cam->params.version.sensor_rev); + + usb_set_intfdata(intf, cam); + + return 0; +} + +/****************************************************************************** + * + * cpia2_disconnect + * + *****************************************************************************/ +static void cpia2_usb_disconnect(struct usb_interface *intf) +{ + struct camera_data *cam = usb_get_intfdata(intf); + usb_set_intfdata(intf, NULL); + cam->present = 0; + + DBG("Stopping stream\n"); + cpia2_usb_stream_stop(cam); + + DBG("Unregistering camera\n"); + cpia2_unregister_camera(cam); + + if(cam->buffers) { + DBG("Wakeup waiting processes\n"); + cam->curbuff->status = FRAME_READY; + cam->curbuff->length = 0; + if (waitqueue_active(&cam->wq_stream)) + wake_up_interruptible(&cam->wq_stream); + } + + DBG("Releasing interface\n"); + usb_driver_release_interface(&cpia2_driver, intf); + + if (cam->open_count == 0) { + DBG("Freeing camera structure\n"); + kfree(cam); + } + + LOG("CPiA2 camera disconnected.\n"); +} + + +/****************************************************************************** + * + * usb_cpia2_init + * + *****************************************************************************/ +int cpia2_usb_init(void) +{ + return usb_register(&cpia2_driver); +} + +/****************************************************************************** + * + * usb_cpia_cleanup + * + *****************************************************************************/ +void cpia2_usb_cleanup(void) +{ + schedule_timeout(2 * HZ); + usb_deregister(&cpia2_driver); +} diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c new file mode 100644 index 00000000000..08f8be345fa --- /dev/null +++ b/drivers/media/video/cpia2/cpia2_v4l.c @@ -0,0 +1,2079 @@ +/**************************************************************************** + * + * Filename: cpia2_v4l.c + * + * Copyright 2001, STMicrolectronics, Inc. + * Contact: steve.miller@st.com + * Copyright 2001,2005, Scott J. Bertin <scottbertin@yahoo.com> + * + * Description: + * This is a USB driver for CPia2 based video cameras. + * The infrastructure of this driver is based on the cpia usb driver by + * Jochen Scharrlach and Johannes Erdfeldt. + * + * 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. + * + * Stripped of 2.4 stuff ready for main kernel submit by + * Alan Cox <alan@redhat.com> + ****************************************************************************/ + +#include <linux/version.h> + +#include <linux/config.h> + +#include <linux/module.h> +#include <linux/time.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/moduleparam.h> + +#include "cpia2.h" +#include "cpia2dev.h" + + +//#define _CPIA2_DEBUG_ + +#define MAKE_STRING_1(x) #x +#define MAKE_STRING(x) MAKE_STRING_1(x) + +static int video_nr = -1; +module_param(video_nr, int, 0); +MODULE_PARM_DESC(video_nr,"video device to register (0=/dev/video0, etc)"); + +static int buffer_size = 68*1024; +module_param(buffer_size, int, 0); +MODULE_PARM_DESC(buffer_size, "Size for each frame buffer in bytes (default 68k)"); + +static int num_buffers = 3; +module_param(num_buffers, int, 0); +MODULE_PARM_DESC(num_buffers, "Number of frame buffers (1-" + MAKE_STRING(VIDEO_MAX_FRAME) ", default 3)"); + +static int alternate = DEFAULT_ALT; +module_param(alternate, int, 0); +MODULE_PARM_DESC(alternate, "USB Alternate (" MAKE_STRING(USBIF_ISO_1) "-" + MAKE_STRING(USBIF_ISO_6) ", default " + MAKE_STRING(DEFAULT_ALT) ")"); + +static int flicker_freq = 60; +module_param(flicker_freq, int, 0); +MODULE_PARM_DESC(flicker_freq, "Flicker frequency (" MAKE_STRING(50) "or" + MAKE_STRING(60) ", default " + MAKE_STRING(60) ")"); + +static int flicker_mode = NEVER_FLICKER; +module_param(flicker_mode, int, 0); +MODULE_PARM_DESC(flicker_mode, + "Flicker supression (" MAKE_STRING(NEVER_FLICKER) "or" + MAKE_STRING(ANTI_FLICKER_ON) ", default " + MAKE_STRING(NEVER_FLICKER) ")"); + +MODULE_AUTHOR("Steve Miller (STMicroelectronics) <steve.miller@st.com>"); +MODULE_DESCRIPTION("V4L-driver for STMicroelectronics CPiA2 based cameras"); +MODULE_SUPPORTED_DEVICE("video"); +MODULE_LICENSE("GPL"); + +#define ABOUT "V4L-Driver for Vision CPiA2 based cameras" + +#ifndef VID_HARDWARE_CPIA2 +#error "VID_HARDWARE_CPIA2 should have been defined in linux/videodev.h" +#endif + +struct control_menu_info { + int value; + char name[32]; +}; + +static struct control_menu_info framerate_controls[] = +{ + { CPIA2_VP_FRAMERATE_6_25, "6.25 fps" }, + { CPIA2_VP_FRAMERATE_7_5, "7.5 fps" }, + { CPIA2_VP_FRAMERATE_12_5, "12.5 fps" }, + { CPIA2_VP_FRAMERATE_15, "15 fps" }, + { CPIA2_VP_FRAMERATE_25, "25 fps" }, + { CPIA2_VP_FRAMERATE_30, "30 fps" }, +}; +#define NUM_FRAMERATE_CONTROLS (sizeof(framerate_controls)/sizeof(framerate_controls[0])) + +static struct control_menu_info flicker_controls[] = +{ + { NEVER_FLICKER, "Off" }, + { FLICKER_50, "50 Hz" }, + { FLICKER_60, "60 Hz" }, +}; +#define NUM_FLICKER_CONTROLS (sizeof(flicker_controls)/sizeof(flicker_controls[0])) + +static struct control_menu_info lights_controls[] = +{ + { 0, "Off" }, + { 64, "Top" }, + { 128, "Bottom" }, + { 192, "Both" }, +}; +#define NUM_LIGHTS_CONTROLS (sizeof(lights_controls)/sizeof(lights_controls[0])) +#define GPIO_LIGHTS_MASK 192 + +static struct v4l2_queryctrl controls[] = { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = DEFAULT_BRIGHTNESS, + }, + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = DEFAULT_CONTRAST, + }, + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = DEFAULT_SATURATION, + }, + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror Horizontally", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Vertically", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, + { + .id = CPIA2_CID_TARGET_KB, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Target KB", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = DEFAULT_TARGET_KB, + }, + { + .id = CPIA2_CID_GPIO, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "GPIO", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 0, + }, + { + .id = CPIA2_CID_FLICKER_MODE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Flicker Reduction", + .minimum = 0, + .maximum = NUM_FLICKER_CONTROLS-1, + .step = 1, + .default_value = 0, + }, + { + .id = CPIA2_CID_FRAMERATE, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Framerate", + .minimum = 0, + .maximum = NUM_FRAMERATE_CONTROLS-1, + .step = 1, + .default_value = NUM_FRAMERATE_CONTROLS-1, + }, + { + .id = CPIA2_CID_USB_ALT, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "USB Alternate", + .minimum = USBIF_ISO_1, + .maximum = USBIF_ISO_6, + .step = 1, + .default_value = DEFAULT_ALT, + }, + { + .id = CPIA2_CID_LIGHTS, + .type = V4L2_CTRL_TYPE_MENU, + .name = "Lights", + .minimum = 0, + .maximum = NUM_LIGHTS_CONTROLS-1, + .step = 1, + .default_value = 0, + }, + { + .id = CPIA2_CID_RESET_CAMERA, + .type = V4L2_CTRL_TYPE_BUTTON, + .name = "Reset Camera", + .minimum = 0, + .maximum = 0, + .step = 0, + .default_value = 0, + }, +}; +#define NUM_CONTROLS (sizeof(controls)/sizeof(controls[0])) + + +/****************************************************************************** + * + * cpia2_open + * + *****************************************************************************/ +static int cpia2_open(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct camera_data *cam = video_get_drvdata(dev); + int retval = 0; + + if (!cam) { + ERR("Internal error, camera_data not found!\n"); + return -ENODEV; + } + + if(down_interruptible(&cam->busy_lock)) + return -ERESTARTSYS; + + if(!cam->present) { + retval = -ENODEV; + goto err_return; + } + + if (cam->open_count > 0) { + goto skip_init; + } + + if (cpia2_allocate_buffers(cam)) { + retval = -ENOMEM; + goto err_return; + } + + /* reset the camera */ + if (cpia2_reset_camera(cam) < 0) { + retval = -EIO; + goto err_return; + } + + cam->APP_len = 0; + cam->COM_len = 0; + +skip_init: + { + struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL); + if(!fh) { + retval = -ENOMEM; + goto err_return; + } + file->private_data = fh; + fh->prio = V4L2_PRIORITY_UNSET; + v4l2_prio_open(&cam->prio, &fh->prio); + fh->mmapped = 0; + } + + ++cam->open_count; + + cpia2_dbg_dump_registers(cam); + +err_return: + up(&cam->busy_lock); + return retval; +} + +/****************************************************************************** + * + * cpia2_close + * + *****************************************************************************/ +static int cpia2_close(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct camera_data *cam = video_get_drvdata(dev); + struct cpia2_fh *fh = file->private_data; + + down(&cam->busy_lock); + + if (cam->present && + (cam->open_count == 1 + || fh->prio == V4L2_PRIORITY_RECORD + )) { + cpia2_usb_stream_stop(cam); + + if(cam->open_count == 1) { + /* save camera state for later open */ + cpia2_save_camera_state(cam); + + cpia2_set_low_power(cam); + cpia2_free_buffers(cam); + } + } + + { + if(fh->mmapped) + cam->mmapped = 0; + v4l2_prio_close(&cam->prio,&fh->prio); + file->private_data = NULL; + kfree(fh); + } + + if (--cam->open_count == 0) { + cpia2_free_buffers(cam); + if (!cam->present) { + video_unregister_device(dev); + kfree(cam); + } + } + + up(&cam->busy_lock); + + return 0; +} + +/****************************************************************************** + * + * cpia2_v4l_read + * + *****************************************************************************/ +static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, + loff_t *off) +{ + struct video_device *dev = video_devdata(file); + struct camera_data *cam = video_get_drvdata(dev); + int noblock = file->f_flags&O_NONBLOCK; + + struct cpia2_fh *fh = file->private_data; + + if(!cam) + return -EINVAL; + + /* Priority check */ + if(fh->prio != V4L2_PRIORITY_RECORD) { + return -EBUSY; + } + + return cpia2_read(cam, buf, count, noblock); +} + + +/****************************************************************************** + * + * cpia2_v4l_poll + * + *****************************************************************************/ +static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct video_device *dev = video_devdata(filp); + struct camera_data *cam = video_get_drvdata(dev); + + struct cpia2_fh *fh = filp->private_data; + + if(!cam) + return POLLERR; + + /* Priority check */ + if(fh->prio != V4L2_PRIORITY_RECORD) { + return POLLERR; + } + + return cpia2_poll(cam, filp, wait); +} + + +/****************************************************************************** + * + * ioctl_cap_query + * + *****************************************************************************/ +static int ioctl_cap_query(void *arg, struct camera_data *cam) +{ + struct video_capability *vc; + int retval = 0; + vc = arg; + + if (cam->params.pnp_id.product == 0x151) + strcpy(vc->name, "QX5 Microscope"); + else + strcpy(vc->name, "CPiA2 Camera"); + + vc->type = VID_TYPE_CAPTURE | VID_TYPE_MJPEG_ENCODER; + vc->channels = 1; + vc->audios = 0; + vc->minwidth = 176; /* VIDEOSIZE_QCIF */ + vc->minheight = 144; + switch (cam->params.version.sensor_flags) { + case CPIA2_VP_SENSOR_FLAGS_500: + vc->maxwidth = STV_IMAGE_VGA_COLS; + vc->maxheight = STV_IMAGE_VGA_ROWS; + break; + case CPIA2_VP_SENSOR_FLAGS_410: + vc->maxwidth = STV_IMAGE_CIF_COLS; + vc->maxheight = STV_IMAGE_CIF_ROWS; + break; + default: + return -EINVAL; + } + + return retval; +} + +/****************************************************************************** + * + * ioctl_get_channel + * + *****************************************************************************/ +static int ioctl_get_channel(void *arg) +{ + int retval = 0; + struct video_channel *v; + v = arg; + + if (v->channel != 0) + return -EINVAL; + + v->channel = 0; + strcpy(v->name, "Camera"); + v->tuners = 0; + v->flags = 0; + v->type = VIDEO_TYPE_CAMERA; + v->norm = 0; + + return retval; +} + +/****************************************************************************** + * + * ioctl_set_channel + * + *****************************************************************************/ +static int ioctl_set_channel(void *arg) +{ + struct video_channel *v; + int retval = 0; + v = arg; + + if (retval == 0 && v->channel != 0) + retval = -EINVAL; + + return retval; +} + +/****************************************************************************** + * + * ioctl_set_image_prop + * + *****************************************************************************/ +static int ioctl_set_image_prop(void *arg, struct camera_data *cam) +{ + struct video_picture *vp; + int retval = 0; + vp = arg; + + /* brightness, color, contrast need no check 0-65535 */ + memcpy(&cam->vp, vp, sizeof(*vp)); + + /* update cam->params.colorParams */ + cam->params.color_params.brightness = vp->brightness / 256; + cam->params.color_params.saturation = vp->colour / 256; + cam->params.color_params.contrast = vp->contrast / 256; + + DBG("Requested params: bright 0x%X, sat 0x%X, contrast 0x%X\n", + cam->params.color_params.brightness, + cam->params.color_params.saturation, + cam->params.color_params.contrast); + + cpia2_set_color_params(cam); + + return retval; +} + +static int sync(struct camera_data *cam, int frame_nr) +{ + struct framebuf *frame = &cam->buffers[frame_nr]; + + while (1) { + if (frame->status == FRAME_READY) + return 0; + + if (!cam->streaming) { + frame->status = FRAME_READY; + frame->length = 0; + return 0; + } + + up(&cam->busy_lock); + wait_event_interruptible(cam->wq_stream, + !cam->streaming || + frame->status == FRAME_READY); + down(&cam->busy_lock); + if (signal_pending(current)) + return -ERESTARTSYS; + if(!cam->present) + return -ENOTTY; + } +} + +/****************************************************************************** + * + * ioctl_set_window_size + * + *****************************************************************************/ +static int ioctl_set_window_size(void *arg, struct camera_data *cam, + struct cpia2_fh *fh) +{ + /* copy_from_user, check validity, copy to internal structure */ + struct video_window *vw; + int frame, err; + vw = arg; + + if (vw->clipcount != 0) /* clipping not supported */ + return -EINVAL; + + if (vw->clips != NULL) /* clipping not supported */ + return -EINVAL; + + /* Ensure that only this process can change the format. */ + err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); + if(err != 0) + return err; + + cam->pixelformat = V4L2_PIX_FMT_JPEG; + + /* Be sure to supply the Huffman tables, this isn't MJPEG */ + cam->params.compression.inhibit_htables = 0; + + /* we set the video window to something smaller or equal to what + * is requested by the user??? + */ + DBG("Requested width = %d, height = %d\n", vw->width, vw->height); + if (vw->width != cam->vw.width || vw->height != cam->vw.height) { + cam->vw.width = vw->width; + cam->vw.height = vw->height; + cam->params.roi.width = vw->width; + cam->params.roi.height = vw->height; + cpia2_set_format(cam); + } + + for (frame = 0; frame < cam->num_frames; ++frame) { + if (cam->buffers[frame].status == FRAME_READING) + if ((err = sync(cam, frame)) < 0) + return err; + + cam->buffers[frame].status = FRAME_EMPTY; + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_get_mbuf + * + *****************************************************************************/ +static int ioctl_get_mbuf(void *arg, struct camera_data *cam) +{ + struct video_mbuf *vm; + int i; + vm = arg; + + memset(vm, 0, sizeof(*vm)); + vm->size = cam->frame_size*cam->num_frames; + vm->frames = cam->num_frames; + for (i = 0; i < cam->num_frames; i++) + vm->offsets[i] = cam->frame_size * i; + + return 0; +} + +/****************************************************************************** + * + * ioctl_mcapture + * + *****************************************************************************/ +static int ioctl_mcapture(void *arg, struct camera_data *cam, + struct cpia2_fh *fh) +{ + struct video_mmap *vm; + int video_size, err; + vm = arg; + + if (vm->frame < 0 || vm->frame >= cam->num_frames) + return -EINVAL; + + /* set video size */ + video_size = cpia2_match_video_size(vm->width, vm->height); + if (cam->video_size < 0) { + return -EINVAL; + } + + /* Ensure that only this process can change the format. */ + err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); + if(err != 0) + return err; + + if (video_size != cam->video_size) { + cam->video_size = video_size; + cam->params.roi.width = vm->width; + cam->params.roi.height = vm->height; + cpia2_set_format(cam); + } + + if (cam->buffers[vm->frame].status == FRAME_READING) + if ((err=sync(cam, vm->frame)) < 0) + return err; + + cam->buffers[vm->frame].status = FRAME_EMPTY; + + return cpia2_usb_stream_start(cam,cam->params.camera_state.stream_mode); +} + +/****************************************************************************** + * + * ioctl_sync + * + *****************************************************************************/ +static int ioctl_sync(void *arg, struct camera_data *cam) +{ + int frame; + + frame = *(int*)arg; + + if (frame < 0 || frame >= cam->num_frames) + return -EINVAL; + + return sync(cam, frame); +} + + +/****************************************************************************** + * + * ioctl_set_gpio + * + *****************************************************************************/ + +static int ioctl_set_gpio(void *arg, struct camera_data *cam) +{ + __u32 gpio_val; + + gpio_val = *(__u32*) arg; + + if (gpio_val &~ 0xFFU) + return -EINVAL; + + return cpia2_set_gpio(cam, (unsigned char)gpio_val); +} + +/****************************************************************************** + * + * ioctl_querycap + * + * V4L2 device capabilities + * + *****************************************************************************/ + +static int ioctl_querycap(void *arg, struct camera_data *cam) +{ + struct v4l2_capability *vc = arg; + + memset(vc, 0, sizeof(*vc)); + strcpy(vc->driver, "cpia2"); + + if (cam->params.pnp_id.product == 0x151) + strcpy(vc->card, "QX5 Microscope"); + else + strcpy(vc->card, "CPiA2 Camera"); + switch (cam->params.pnp_id.device_type) { + case DEVICE_STV_672: + strcat(vc->card, " (672/"); + break; + case DEVICE_STV_676: + strcat(vc->card, " (676/"); + break; + default: + strcat(vc->card, " (???/"); + break; + } + switch (cam->params.version.sensor_flags) { + case CPIA2_VP_SENSOR_FLAGS_404: + strcat(vc->card, "404)"); + break; + case CPIA2_VP_SENSOR_FLAGS_407: + strcat(vc->card, "407)"); + break; + case CPIA2_VP_SENSOR_FLAGS_409: + strcat(vc->card, "409)"); + break; + case CPIA2_VP_SENSOR_FLAGS_410: + strcat(vc->card, "410)"); + break; + case CPIA2_VP_SENSOR_FLAGS_500: + strcat(vc->card, "500)"); + break; + default: + strcat(vc->card, "???)"); + break; + } + + if (usb_make_path(cam->dev, vc->bus_info, sizeof(vc->bus_info)) <0) + memset(vc->bus_info,0, sizeof(vc->bus_info)); + + vc->version = KERNEL_VERSION(CPIA2_MAJ_VER, CPIA2_MIN_VER, + CPIA2_PATCH_VER); + + vc->capabilities = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; + + return 0; +} + +/****************************************************************************** + * + * ioctl_input + * + * V4L2 input get/set/enumerate + * + *****************************************************************************/ + +static int ioctl_input(unsigned int ioclt_nr,void *arg,struct camera_data *cam) +{ + struct v4l2_input *i = arg; + + if(ioclt_nr != VIDIOC_G_INPUT) { + if (i->index != 0) + return -EINVAL; + } + + memset(i, 0, sizeof(*i)); + strcpy(i->name, "Camera"); + i->type = V4L2_INPUT_TYPE_CAMERA; + + return 0; +} + +/****************************************************************************** + * + * ioctl_enum_fmt + * + * V4L2 format enumerate + * + *****************************************************************************/ + +static int ioctl_enum_fmt(void *arg,struct camera_data *cam) +{ + struct v4l2_fmtdesc *f = arg; + int index = f->index; + + if (index < 0 || index > 1) + return -EINVAL; + + memset(f, 0, sizeof(*f)); + f->index = index; + f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + f->flags = V4L2_FMT_FLAG_COMPRESSED; + switch(index) { + case 0: + strcpy(f->description, "MJPEG"); + f->pixelformat = V4L2_PIX_FMT_MJPEG; + break; + case 1: + strcpy(f->description, "JPEG"); + f->pixelformat = V4L2_PIX_FMT_JPEG; + break; + default: + return -EINVAL; + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_try_fmt + * + * V4L2 format try + * + *****************************************************************************/ + +static int ioctl_try_fmt(void *arg,struct camera_data *cam) +{ + struct v4l2_format *f = arg; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG && + f->fmt.pix.pixelformat != V4L2_PIX_FMT_JPEG) + return -EINVAL; + + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = cam->frame_size; + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; + f->fmt.pix.priv = 0; + + switch (cpia2_match_video_size(f->fmt.pix.width, f->fmt.pix.height)) { + case VIDEOSIZE_VGA: + f->fmt.pix.width = 640; + f->fmt.pix.height = 480; + break; + case VIDEOSIZE_CIF: + f->fmt.pix.width = 352; + f->fmt.pix.height = 288; + break; + case VIDEOSIZE_QVGA: + f->fmt.pix.width = 320; + f->fmt.pix.height = 240; + break; + case VIDEOSIZE_288_216: + f->fmt.pix.width = 288; + f->fmt.pix.height = 216; + break; + case VIDEOSIZE_256_192: + f->fmt.pix.width = 256; + f->fmt.pix.height = 192; + break; + case VIDEOSIZE_224_168: + f->fmt.pix.width = 224; + f->fmt.pix.height = 168; + break; + case VIDEOSIZE_192_144: + f->fmt.pix.width = 192; + f->fmt.pix.height = 144; + break; + case VIDEOSIZE_QCIF: + default: + f->fmt.pix.width = 176; + f->fmt.pix.height = 144; + break; + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_set_fmt + * + * V4L2 format set + * + *****************************************************************************/ + +static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh) +{ + struct v4l2_format *f = arg; + int err, frame; + + err = ioctl_try_fmt(arg, cam); + if(err != 0) + return err; + + /* Ensure that only this process can change the format. */ + err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD); + if(err != 0) { + return err; + } + + cam->pixelformat = f->fmt.pix.pixelformat; + + /* NOTE: This should be set to 1 for MJPEG, but some apps don't handle + * the missing Huffman table properly. */ + cam->params.compression.inhibit_htables = 0; + /*f->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG;*/ + + /* we set the video window to something smaller or equal to what + * is requested by the user??? + */ + DBG("Requested width = %d, height = %d\n", + f->fmt.pix.width, f->fmt.pix.height); + if (f->fmt.pix.width != cam->vw.width || + f->fmt.pix.height != cam->vw.height) { + cam->vw.width = f->fmt.pix.width; + cam->vw.height = f->fmt.pix.height; + cam->params.roi.width = f->fmt.pix.width; + cam->params.roi.height = f->fmt.pix.height; + cpia2_set_format(cam); + } + + for (frame = 0; frame < cam->num_frames; ++frame) { + if (cam->buffers[frame].status == FRAME_READING) + if ((err = sync(cam, frame)) < 0) + return err; + + cam->buffers[frame].status = FRAME_EMPTY; + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_get_fmt + * + * V4L2 format get + * + *****************************************************************************/ + +static int ioctl_get_fmt(void *arg,struct camera_data *cam) +{ + struct v4l2_format *f = arg; + + if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + f->fmt.pix.width = cam->vw.width; + f->fmt.pix.height = cam->vw.height; + f->fmt.pix.pixelformat = cam->pixelformat; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.bytesperline = 0; + f->fmt.pix.sizeimage = cam->frame_size; + f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; + f->fmt.pix.priv = 0; + + return 0; +} + +/****************************************************************************** + * + * ioctl_cropcap + * + * V4L2 query cropping capabilities + * NOTE: cropping is currently disabled + * + *****************************************************************************/ + +static int ioctl_cropcap(void *arg,struct camera_data *cam) +{ + struct v4l2_cropcap *c = arg; + + if (c->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + c->bounds.left = 0; + c->bounds.top = 0; + c->bounds.width = cam->vw.width; + c->bounds.height = cam->vw.height; + c->defrect.left = 0; + c->defrect.top = 0; + c->defrect.width = cam->vw.width; + c->defrect.height = cam->vw.height; + c->pixelaspect.numerator = 1; + c->pixelaspect.denominator = 1; + + return 0; +} + +/****************************************************************************** + * + * ioctl_queryctrl + * + * V4L2 query possible control variables + * + *****************************************************************************/ + +static int ioctl_queryctrl(void *arg,struct camera_data *cam) +{ + struct v4l2_queryctrl *c = arg; + int i; + + for(i=0; i<NUM_CONTROLS; ++i) { + if(c->id == controls[i].id) { + memcpy(c, controls+i, sizeof(*c)); + break; + } + } + + if(i == NUM_CONTROLS) + return -EINVAL; + + /* Some devices have additional limitations */ + switch(c->id) { + case V4L2_CID_BRIGHTNESS: + /*** + * Don't let the register be set to zero - bug in VP4 + * flash of full brightness + ***/ + if (cam->params.pnp_id.device_type == DEVICE_STV_672) + c->minimum = 1; + break; + case V4L2_CID_VFLIP: + // VP5 Only + if(cam->params.pnp_id.device_type == DEVICE_STV_672) + c->flags |= V4L2_CTRL_FLAG_DISABLED; + break; + case CPIA2_CID_FRAMERATE: + if(cam->params.pnp_id.device_type == DEVICE_STV_672 && + cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ + // Maximum 15fps + int i; + for(i=0; i<c->maximum; ++i) { + if(framerate_controls[i].value == + CPIA2_VP_FRAMERATE_15) { + c->maximum = i; + c->default_value = i; + } + } + } + break; + case CPIA2_CID_FLICKER_MODE: + // Flicker control only valid for 672. + if(cam->params.pnp_id.device_type != DEVICE_STV_672) + c->flags |= V4L2_CTRL_FLAG_DISABLED; + break; + case CPIA2_CID_LIGHTS: + // Light control only valid for the QX5 Microscope. + if(cam->params.pnp_id.product != 0x151) + c->flags |= V4L2_CTRL_FLAG_DISABLED; + break; + default: + break; + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_querymenu + * + * V4L2 query possible control variables + * + *****************************************************************************/ + +static int ioctl_querymenu(void *arg,struct camera_data *cam) +{ + struct v4l2_querymenu *m = arg; + + memset(m->name, 0, sizeof(m->name)); + m->reserved = 0; + + switch(m->id) { + case CPIA2_CID_FLICKER_MODE: + if(m->index < 0 || m->index >= NUM_FLICKER_CONTROLS) + return -EINVAL; + + strcpy(m->name, flicker_controls[m->index].name); + break; + case CPIA2_CID_FRAMERATE: + { + int maximum = NUM_FRAMERATE_CONTROLS - 1; + if(cam->params.pnp_id.device_type == DEVICE_STV_672 && + cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ + // Maximum 15fps + int i; + for(i=0; i<maximum; ++i) { + if(framerate_controls[i].value == + CPIA2_VP_FRAMERATE_15) + maximum = i; + } + } + if(m->index < 0 || m->index > maximum) + return -EINVAL; + + strcpy(m->name, framerate_controls[m->index].name); + break; + } + case CPIA2_CID_LIGHTS: + if(m->index < 0 || m->index >= NUM_LIGHTS_CONTROLS) + return -EINVAL; + + strcpy(m->name, lights_controls[m->index].name); + break; + default: + return -EINVAL; + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_g_ctrl + * + * V4L2 get the value of a control variable + * + *****************************************************************************/ + +static int ioctl_g_ctrl(void *arg,struct camera_data *cam) +{ + struct v4l2_control *c = arg; + + switch(c->id) { + case V4L2_CID_BRIGHTNESS: + cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, + TRANSFER_READ, 0); + c->value = cam->params.color_params.brightness; + break; + case V4L2_CID_CONTRAST: + cpia2_do_command(cam, CPIA2_CMD_GET_CONTRAST, + TRANSFER_READ, 0); + c->value = cam->params.color_params.contrast; + break; + case V4L2_CID_SATURATION: + cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, + TRANSFER_READ, 0); + c->value = cam->params.color_params.saturation; + break; + case V4L2_CID_HFLIP: + cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, + TRANSFER_READ, 0); + c->value = (cam->params.vp_params.user_effects & + CPIA2_VP_USER_EFFECTS_MIRROR) != 0; + break; + case V4L2_CID_VFLIP: + cpia2_do_command(cam, CPIA2_CMD_GET_USER_EFFECTS, + TRANSFER_READ, 0); + c->value = (cam->params.vp_params.user_effects & + CPIA2_VP_USER_EFFECTS_FLIP) != 0; + break; + case CPIA2_CID_TARGET_KB: + c->value = cam->params.vc_params.target_kb; + break; + case CPIA2_CID_GPIO: + cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, + TRANSFER_READ, 0); + c->value = cam->params.vp_params.gpio_data; + break; + case CPIA2_CID_FLICKER_MODE: + { + int i, mode; + cpia2_do_command(cam, CPIA2_CMD_GET_FLICKER_MODES, + TRANSFER_READ, 0); + if(cam->params.flicker_control.cam_register & + CPIA2_VP_FLICKER_MODES_NEVER_FLICKER) { + mode = NEVER_FLICKER; + } else { + if(cam->params.flicker_control.cam_register & + CPIA2_VP_FLICKER_MODES_50HZ) { + mode = FLICKER_50; + } else { + mode = FLICKER_60; + } + } + for(i=0; i<NUM_FLICKER_CONTROLS; i++) { + if(flicker_controls[i].value == mode) { + c->value = i; + break; + } + } + if(i == NUM_FLICKER_CONTROLS) + return -EINVAL; + break; + } + case CPIA2_CID_FRAMERATE: + { + int maximum = NUM_FRAMERATE_CONTROLS - 1; + int i; + for(i=0; i<= maximum; i++) { + if(cam->params.vp_params.frame_rate == + framerate_controls[i].value) + break; + } + if(i > maximum) + return -EINVAL; + c->value = i; + break; + } + case CPIA2_CID_USB_ALT: + c->value = cam->params.camera_state.stream_mode; + break; + case CPIA2_CID_LIGHTS: + { + int i; + cpia2_do_command(cam, CPIA2_CMD_GET_VP_GPIO_DATA, + TRANSFER_READ, 0); + for(i=0; i<NUM_LIGHTS_CONTROLS; i++) { + if((cam->params.vp_params.gpio_data&GPIO_LIGHTS_MASK) == + lights_controls[i].value) { + break; + } + } + if(i == NUM_LIGHTS_CONTROLS) + return -EINVAL; + c->value = i; + break; + } + case CPIA2_CID_RESET_CAMERA: + return -EINVAL; + default: + return -EINVAL; + } + + DBG("Get control id:%d, value:%d\n", c->id, c->value); + + return 0; +} + +/****************************************************************************** + * + * ioctl_s_ctrl + * + * V4L2 set the value of a control variable + * + *****************************************************************************/ + +static int ioctl_s_ctrl(void *arg,struct camera_data *cam) +{ + struct v4l2_control *c = arg; + int i; + int retval = 0; + + DBG("Set control id:%d, value:%d\n", c->id, c->value); + + /* Check that the value is in range */ + for(i=0; i<NUM_CONTROLS; i++) { + if(c->id == controls[i].id) { + if(c->value < controls[i].minimum || + c->value > controls[i].maximum) { + return -EINVAL; + } + break; + } + } + if(i == NUM_CONTROLS) + return -EINVAL; + + switch(c->id) { + case V4L2_CID_BRIGHTNESS: + cpia2_set_brightness(cam, c->value); + break; + case V4L2_CID_CONTRAST: + cpia2_set_contrast(cam, c->value); + break; + case V4L2_CID_SATURATION: + cpia2_set_saturation(cam, c->value); + break; + case V4L2_CID_HFLIP: + cpia2_set_property_mirror(cam, c->value); + break; + case V4L2_CID_VFLIP: + cpia2_set_property_flip(cam, c->value); + break; + case CPIA2_CID_TARGET_KB: + retval = cpia2_set_target_kb(cam, c->value); + break; + case CPIA2_CID_GPIO: + retval = cpia2_set_gpio(cam, c->value); + break; + case CPIA2_CID_FLICKER_MODE: + retval = cpia2_set_flicker_mode(cam, + flicker_controls[c->value].value); + break; + case CPIA2_CID_FRAMERATE: + retval = cpia2_set_fps(cam, framerate_controls[c->value].value); + break; + case CPIA2_CID_USB_ALT: + retval = cpia2_usb_change_streaming_alternate(cam, c->value); + break; + case CPIA2_CID_LIGHTS: + retval = cpia2_set_gpio(cam, lights_controls[c->value].value); + break; + case CPIA2_CID_RESET_CAMERA: + cpia2_usb_stream_pause(cam); + cpia2_reset_camera(cam); + cpia2_usb_stream_resume(cam); + break; + default: + retval = -EINVAL; + } + + return retval; +} + +/****************************************************************************** + * + * ioctl_g_jpegcomp + * + * V4L2 get the JPEG compression parameters + * + *****************************************************************************/ + +static int ioctl_g_jpegcomp(void *arg,struct camera_data *cam) +{ + struct v4l2_jpegcompression *parms = arg; + + memset(parms, 0, sizeof(*parms)); + + parms->quality = 80; // TODO: Can this be made meaningful? + + parms->jpeg_markers = V4L2_JPEG_MARKER_DQT | V4L2_JPEG_MARKER_DRI; + if(!cam->params.compression.inhibit_htables) { + parms->jpeg_markers |= V4L2_JPEG_MARKER_DHT; + } + + parms->APPn = cam->APPn; + parms->APP_len = cam->APP_len; + if(cam->APP_len > 0) { + memcpy(parms->APP_data, cam->APP_data, cam->APP_len); + parms->jpeg_markers |= V4L2_JPEG_MARKER_APP; + } + + parms->COM_len = cam->COM_len; + if(cam->COM_len > 0) { + memcpy(parms->COM_data, cam->COM_data, cam->COM_len); + parms->jpeg_markers |= JPEG_MARKER_COM; + } + + DBG("G_JPEGCOMP APP_len:%d COM_len:%d\n", + parms->APP_len, parms->COM_len); + + return 0; +} + +/****************************************************************************** + * + * ioctl_s_jpegcomp + * + * V4L2 set the JPEG compression parameters + * NOTE: quality and some jpeg_markers are ignored. + * + *****************************************************************************/ + +static int ioctl_s_jpegcomp(void *arg,struct camera_data *cam) +{ + struct v4l2_jpegcompression *parms = arg; + + DBG("S_JPEGCOMP APP_len:%d COM_len:%d\n", + parms->APP_len, parms->COM_len); + + cam->params.compression.inhibit_htables = + !(parms->jpeg_markers & V4L2_JPEG_MARKER_DHT); + + if(parms->APP_len != 0) { + if(parms->APP_len > 0 && + parms->APP_len <= sizeof(cam->APP_data) && + parms->APPn >= 0 && parms->APPn <= 15) { + cam->APPn = parms->APPn; + cam->APP_len = parms->APP_len; + memcpy(cam->APP_data, parms->APP_data, parms->APP_len); + } else { + LOG("Bad APPn Params n=%d len=%d\n", + parms->APPn, parms->APP_len); + return -EINVAL; + } + } else { + cam->APP_len = 0; + } + + if(parms->COM_len != 0) { + if(parms->COM_len > 0 && + parms->COM_len <= sizeof(cam->COM_data)) { + cam->COM_len = parms->COM_len; + memcpy(cam->COM_data, parms->COM_data, parms->COM_len); + } else { + LOG("Bad COM_len=%d\n", parms->COM_len); + return -EINVAL; + } + } + + return 0; +} + +/****************************************************************************** + * + * ioctl_reqbufs + * + * V4L2 Initiate memory mapping. + * NOTE: The user's request is ignored. For now the buffers are fixed. + * + *****************************************************************************/ + +static int ioctl_reqbufs(void *arg,struct camera_data *cam) +{ + struct v4l2_requestbuffers *req = arg; + + if(req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + req->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + DBG("REQBUFS requested:%d returning:%d\n", req->count, cam->num_frames); + req->count = cam->num_frames; + memset(&req->reserved, 0, sizeof(req->reserved)); + + return 0; +} + +/****************************************************************************** + * + * ioctl_querybuf + * + * V4L2 Query memory buffer status. + * + *****************************************************************************/ + +static int ioctl_querybuf(void *arg,struct camera_data *cam) +{ + struct v4l2_buffer *buf = arg; + + if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + buf->index > cam->num_frames) + return -EINVAL; + + buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; + buf->length = cam->frame_size; + + buf->memory = V4L2_MEMORY_MMAP; + + if(cam->mmapped) + buf->flags = V4L2_BUF_FLAG_MAPPED; + else + buf->flags = 0; + + switch (cam->buffers[buf->index].status) { + case FRAME_EMPTY: + case FRAME_ERROR: + case FRAME_READING: + buf->bytesused = 0; + buf->flags = V4L2_BUF_FLAG_QUEUED; + break; + case FRAME_READY: + buf->bytesused = cam->buffers[buf->index].length; + buf->timestamp = cam->buffers[buf->index].timestamp; + buf->sequence = cam->buffers[buf->index].seq; + buf->flags = V4L2_BUF_FLAG_DONE; + break; + } + + DBG("QUERYBUF index:%d offset:%d flags:%d seq:%d bytesused:%d\n", + buf->index, buf->m.offset, buf->flags, buf->sequence, + buf->bytesused); + + return 0; +} + +/****************************************************************************** + * + * ioctl_qbuf + * + * V4L2 User is freeing buffer + * + *****************************************************************************/ + +static int ioctl_qbuf(void *arg,struct camera_data *cam) +{ + struct v4l2_buffer *buf = arg; + + if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + buf->memory != V4L2_MEMORY_MMAP || + buf->index > cam->num_frames) + return -EINVAL; + + DBG("QBUF #%d\n", buf->index); + + if(cam->buffers[buf->index].status == FRAME_READY) + cam->buffers[buf->index].status = FRAME_EMPTY; + + return 0; +} + +/****************************************************************************** + * + * find_earliest_filled_buffer + * + * Helper for ioctl_dqbuf. Find the next ready buffer. + * + *****************************************************************************/ + +static int find_earliest_filled_buffer(struct camera_data *cam) +{ + int i; + int found = -1; + for (i=0; i<cam->num_frames; i++) { + if(cam->buffers[i].status == FRAME_READY) { + if(found < 0) { + found = i; + } else { + /* find which buffer is earlier */ + struct timeval *tv1, *tv2; + tv1 = &cam->buffers[i].timestamp; + tv2 = &cam->buffers[found].timestamp; + if(tv1->tv_sec < tv2->tv_sec || + (tv1->tv_sec == tv2->tv_sec && + tv1->tv_usec < tv2->tv_usec)) + found = i; + } + } + } + return found; +} + +/****************************************************************************** + * + * ioctl_dqbuf + * + * V4L2 User is asking for a filled buffer. + * + *****************************************************************************/ + +static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file) +{ + struct v4l2_buffer *buf = arg; + int frame; + + if(buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + buf->memory != V4L2_MEMORY_MMAP) + return -EINVAL; + + frame = find_earliest_filled_buffer(cam); + + if(frame < 0 && file->f_flags&O_NONBLOCK) + return -EAGAIN; + + if(frame < 0) { + /* Wait for a frame to become available */ + struct framebuf *cb=cam->curbuff; + up(&cam->busy_lock); + wait_event_interruptible(cam->wq_stream, + !cam->present || + (cb=cam->curbuff)->status == FRAME_READY); + down(&cam->busy_lock); + if (signal_pending(current)) + return -ERESTARTSYS; + if(!cam->present) + return -ENOTTY; + frame = cb->num; + } + + + buf->index = frame; + buf->bytesused = cam->buffers[buf->index].length; + buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_DONE; + buf->field = V4L2_FIELD_NONE; + buf->timestamp = cam->buffers[buf->index].timestamp; + buf->sequence = cam->buffers[buf->index].seq; + buf->m.offset = cam->buffers[buf->index].data - cam->frame_buffer; + buf->length = cam->frame_size; + buf->input = 0; + buf->reserved = 0; + memset(&buf->timecode, 0, sizeof(buf->timecode)); + + DBG("DQBUF #%d status:%d seq:%d length:%d\n", buf->index, + cam->buffers[buf->index].status, buf->sequence, buf->bytesused); + + return 0; +} + +/****************************************************************************** + * + * cpia2_ioctl + * + *****************************************************************************/ +static int cpia2_do_ioctl(struct inode *inode, struct file *file, + unsigned int ioctl_nr, void *arg) +{ + struct video_device *dev = video_devdata(file); + struct camera_data *cam = video_get_drvdata(dev); + int retval = 0; + + if (!cam) + return -ENOTTY; + + /* make this _really_ smp-safe */ + if (down_interruptible(&cam->busy_lock)) + return -ERESTARTSYS; + + if (!cam->present) { + up(&cam->busy_lock); + return -ENODEV; + } + + /* Priority check */ + switch (ioctl_nr) { + case VIDIOCSWIN: + case VIDIOCMCAPTURE: + case VIDIOC_S_FMT: + { + struct cpia2_fh *fh = file->private_data; + retval = v4l2_prio_check(&cam->prio, &fh->prio); + if(retval) { + up(&cam->busy_lock); + return retval; + } + break; + } + case VIDIOCGMBUF: + case VIDIOCSYNC: + { + struct cpia2_fh *fh = file->private_data; + if(fh->prio != V4L2_PRIORITY_RECORD) { + up(&cam->busy_lock); + return -EBUSY; + } + break; + } + default: + break; + } + + switch (ioctl_nr) { + case VIDIOCGCAP: /* query capabilities */ + retval = ioctl_cap_query(arg, cam); + break; + + case VIDIOCGCHAN: /* get video source - we are a camera, nothing else */ + retval = ioctl_get_channel(arg); + break; + case VIDIOCSCHAN: /* set video source - we are a camera, nothing else */ + retval = ioctl_set_channel(arg); + break; + case VIDIOCGPICT: /* image properties */ + memcpy(arg, &cam->vp, sizeof(struct video_picture)); + break; + case VIDIOCSPICT: + retval = ioctl_set_image_prop(arg, cam); + break; + case VIDIOCGWIN: /* get/set capture window */ + memcpy(arg, &cam->vw, sizeof(struct video_window)); + break; + case VIDIOCSWIN: + retval = ioctl_set_window_size(arg, cam, file->private_data); + break; + case VIDIOCGMBUF: /* mmap interface */ + retval = ioctl_get_mbuf(arg, cam); + break; + case VIDIOCMCAPTURE: + retval = ioctl_mcapture(arg, cam, file->private_data); + break; + case VIDIOCSYNC: + retval = ioctl_sync(arg, cam); + break; + /* pointless to implement overlay with this camera */ + case VIDIOCCAPTURE: + case VIDIOCGFBUF: + case VIDIOCSFBUF: + case VIDIOCKEY: + retval = -EINVAL; + break; + + /* tuner interface - we have none */ + case VIDIOCGTUNER: + case VIDIOCSTUNER: + case VIDIOCGFREQ: + case VIDIOCSFREQ: + retval = -EINVAL; + break; + + /* audio interface - we have none */ + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + retval = -EINVAL; + break; + + /* CPIA2 extension to Video4Linux API */ + case CPIA2_IOC_SET_GPIO: + retval = ioctl_set_gpio(arg, cam); + break; + case VIDIOC_QUERYCAP: + retval = ioctl_querycap(arg,cam); + break; + + case VIDIOC_ENUMINPUT: + case VIDIOC_G_INPUT: + case VIDIOC_S_INPUT: + retval = ioctl_input(ioctl_nr, arg,cam); + break; + + case VIDIOC_ENUM_FMT: + retval = ioctl_enum_fmt(arg,cam); + break; + case VIDIOC_TRY_FMT: + retval = ioctl_try_fmt(arg,cam); + break; + case VIDIOC_G_FMT: + retval = ioctl_get_fmt(arg,cam); + break; + case VIDIOC_S_FMT: + retval = ioctl_set_fmt(arg,cam,file->private_data); + break; + + case VIDIOC_CROPCAP: + retval = ioctl_cropcap(arg,cam); + break; + case VIDIOC_G_CROP: + case VIDIOC_S_CROP: + // TODO: I think cropping can be implemented - SJB + retval = -EINVAL; + break; + + case VIDIOC_QUERYCTRL: + retval = ioctl_queryctrl(arg,cam); + break; + case VIDIOC_QUERYMENU: + retval = ioctl_querymenu(arg,cam); + break; + case VIDIOC_G_CTRL: + retval = ioctl_g_ctrl(arg,cam); + break; + case VIDIOC_S_CTRL: + retval = ioctl_s_ctrl(arg,cam); + break; + + case VIDIOC_G_JPEGCOMP: + retval = ioctl_g_jpegcomp(arg,cam); + break; + case VIDIOC_S_JPEGCOMP: + retval = ioctl_s_jpegcomp(arg,cam); + break; + + case VIDIOC_G_PRIORITY: + { + struct cpia2_fh *fh = file->private_data; + *(enum v4l2_priority*)arg = fh->prio; + break; + } + case VIDIOC_S_PRIORITY: + { + struct cpia2_fh *fh = file->private_data; + enum v4l2_priority prio; + prio = *(enum v4l2_priority*)arg; + if(cam->streaming && + prio != fh->prio && + fh->prio == V4L2_PRIORITY_RECORD) { + /* Can't drop record priority while streaming */ + retval = -EBUSY; + } else if(prio == V4L2_PRIORITY_RECORD && + prio != fh->prio && + v4l2_prio_max(&cam->prio) == V4L2_PRIORITY_RECORD) { + /* Only one program can record at a time */ + retval = -EBUSY; + } else { + retval = v4l2_prio_change(&cam->prio, &fh->prio, prio); + } + break; + } + + case VIDIOC_REQBUFS: + retval = ioctl_reqbufs(arg,cam); + break; + case VIDIOC_QUERYBUF: + retval = ioctl_querybuf(arg,cam); + break; + case VIDIOC_QBUF: + retval = ioctl_qbuf(arg,cam); + break; + case VIDIOC_DQBUF: + retval = ioctl_dqbuf(arg,cam,file); + break; + case VIDIOC_STREAMON: + { + int type; + DBG("VIDIOC_STREAMON, streaming=%d\n", cam->streaming); + type = *(int*)arg; + if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + retval = -EINVAL; + + if(!cam->streaming) { + retval = cpia2_usb_stream_start(cam, + cam->params.camera_state.stream_mode); + } else { + retval = -EINVAL; + } + + break; + } + case VIDIOC_STREAMOFF: + { + int type; + DBG("VIDIOC_STREAMOFF, streaming=%d\n", cam->streaming); + type = *(int*)arg; + if(!cam->mmapped || type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + retval = -EINVAL; + + if(cam->streaming) { + retval = cpia2_usb_stream_stop(cam); + } else { + retval = -EINVAL; + } + + break; + } + + case VIDIOC_ENUMOUTPUT: + case VIDIOC_G_OUTPUT: + case VIDIOC_S_OUTPUT: + case VIDIOC_G_MODULATOR: + case VIDIOC_S_MODULATOR: + + case VIDIOC_ENUMAUDIO: + case VIDIOC_G_AUDIO: + case VIDIOC_S_AUDIO: + + case VIDIOC_ENUMAUDOUT: + case VIDIOC_G_AUDOUT: + case VIDIOC_S_AUDOUT: + + case VIDIOC_ENUMSTD: + case VIDIOC_QUERYSTD: + case VIDIOC_G_STD: + case VIDIOC_S_STD: + + case VIDIOC_G_TUNER: + case VIDIOC_S_TUNER: + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + + case VIDIOC_OVERLAY: + case VIDIOC_G_FBUF: + case VIDIOC_S_FBUF: + + case VIDIOC_G_PARM: + case VIDIOC_S_PARM: + retval = -EINVAL; + break; + default: + retval = -ENOIOCTLCMD; + break; + } + + up(&cam->busy_lock); + return retval; +} + +static int cpia2_ioctl(struct inode *inode, struct file *file, + unsigned int ioctl_nr, unsigned long iarg) +{ + return video_usercopy(inode, file, ioctl_nr, iarg, cpia2_do_ioctl); +} + +/****************************************************************************** + * + * cpia2_mmap + * + *****************************************************************************/ +static int cpia2_mmap(struct file *file, struct vm_area_struct *area) +{ + int retval; + struct video_device *dev = video_devdata(file); + struct camera_data *cam = video_get_drvdata(dev); + + /* Priority check */ + struct cpia2_fh *fh = file->private_data; + if(fh->prio != V4L2_PRIORITY_RECORD) { + return -EBUSY; + } + + retval = cpia2_remap_buffer(cam, area); + + if(!retval) + fh->mmapped = 1; + return retval; +} + +/****************************************************************************** + * + * reset_camera_struct_v4l + * + * Sets all values to the defaults + *****************************************************************************/ +static void reset_camera_struct_v4l(struct camera_data *cam) +{ + /*** + * Fill in the v4l structures. video_cap is filled in inside the VIDIOCCAP + * Ioctl. Here, just do the window and picture stucts. + ***/ + cam->vp.palette = (u16) VIDEO_PALETTE_RGB24; /* Is this right? */ + cam->vp.brightness = (u16) cam->params.color_params.brightness * 256; + cam->vp.colour = (u16) cam->params.color_params.saturation * 256; + cam->vp.contrast = (u16) cam->params.color_params.contrast * 256; + + cam->vw.x = 0; + cam->vw.y = 0; + cam->vw.width = cam->params.roi.width; + cam->vw.height = cam->params.roi.height; + cam->vw.flags = 0; + cam->vw.clipcount = 0; + + cam->frame_size = buffer_size; + cam->num_frames = num_buffers; + + /* FlickerModes */ + cam->params.flicker_control.flicker_mode_req = flicker_mode; + cam->params.flicker_control.mains_frequency = flicker_freq; + + /* streamMode */ + cam->params.camera_state.stream_mode = alternate; + + cam->pixelformat = V4L2_PIX_FMT_JPEG; + v4l2_prio_init(&cam->prio); + return; +} + +/*** + * The v4l video device structure initialized for this device + ***/ +static struct file_operations fops_template = { + .owner= THIS_MODULE, + .open= cpia2_open, + .release= cpia2_close, + .read= cpia2_v4l_read, + .poll= cpia2_v4l_poll, + .ioctl= cpia2_ioctl, + .llseek= no_llseek, + .mmap= cpia2_mmap, +}; + +static struct video_device cpia2_template = { + /* I could not find any place for the old .initialize initializer?? */ + .owner= THIS_MODULE, + .name= "CPiA2 Camera", + .type= VID_TYPE_CAPTURE, + .type2 = V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_STREAMING, + .hardware= VID_HARDWARE_CPIA2, + .minor= -1, + .fops= &fops_template, + .release= video_device_release, +}; + +/****************************************************************************** + * + * cpia2_register_camera + * + *****************************************************************************/ +int cpia2_register_camera(struct camera_data *cam) +{ + cam->vdev = video_device_alloc(); + if(!cam->vdev) + return -ENOMEM; + + memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template)); + video_set_drvdata(cam->vdev, cam); + + reset_camera_struct_v4l(cam); + + /* register v4l device */ + if (video_register_device + (cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + ERR("video_register_device failed\n"); + video_device_release(cam->vdev); + return -ENODEV; + } + + return 0; +} + +/****************************************************************************** + * + * cpia2_unregister_camera + * + *****************************************************************************/ +void cpia2_unregister_camera(struct camera_data *cam) +{ + if (!cam->open_count) { + video_unregister_device(cam->vdev); + } else { + LOG("/dev/video%d removed while open, " + "deferring video_unregister_device\n", + cam->vdev->minor); + } +} + +/****************************************************************************** + * + * check_parameters + * + * Make sure that all user-supplied parameters are sensible + *****************************************************************************/ +static void __init check_parameters(void) +{ + if(buffer_size < PAGE_SIZE) { + buffer_size = PAGE_SIZE; + LOG("buffer_size too small, setting to %d\n", buffer_size); + } else if(buffer_size > 1024*1024) { + /* arbitrary upper limiit */ + buffer_size = 1024*1024; + LOG("buffer_size ridiculously large, setting to %d\n", + buffer_size); + } else { + buffer_size += PAGE_SIZE-1; + buffer_size &= ~(PAGE_SIZE-1); + } + + if(num_buffers < 1) { + num_buffers = 1; + LOG("num_buffers too small, setting to %d\n", num_buffers); + } else if(num_buffers > VIDEO_MAX_FRAME) { + num_buffers = VIDEO_MAX_FRAME; + LOG("num_buffers too large, setting to %d\n", num_buffers); + } + + if(alternate < USBIF_ISO_1 || alternate > USBIF_ISO_6) { + alternate = DEFAULT_ALT; + LOG("alternate specified is invalid, using %d\n", alternate); + } + + if (flicker_mode != NEVER_FLICKER && flicker_mode != ANTI_FLICKER_ON) { + flicker_mode = NEVER_FLICKER; + LOG("Flicker mode specified is invalid, using %d\n", + flicker_mode); + } + + if (flicker_freq != FLICKER_50 && flicker_freq != FLICKER_60) { + flicker_freq = FLICKER_60; + LOG("Flicker mode specified is invalid, using %d\n", + flicker_freq); + } + + if(video_nr < -1 || video_nr > 64) { + video_nr = -1; + LOG("invalid video_nr specified, must be -1 to 64\n"); + } + + DBG("Using %d buffers, each %d bytes, alternate=%d\n", + num_buffers, buffer_size, alternate); +} + +/************ Module Stuff ***************/ + + +/****************************************************************************** + * + * cpia2_init/module_init + * + *****************************************************************************/ +static int __init cpia2_init(void) +{ + LOG("%s v%d.%d.%d\n", + ABOUT, CPIA2_MAJ_VER, CPIA2_MIN_VER, CPIA2_PATCH_VER); + check_parameters(); + cpia2_usb_init(); + return 0; +} + + +/****************************************************************************** + * + * cpia2_exit/module_exit + * + *****************************************************************************/ +static void __exit cpia2_exit(void) +{ + cpia2_usb_cleanup(); + schedule_timeout(2 * HZ); +} + +module_init(cpia2_init); +module_exit(cpia2_exit); + diff --git a/drivers/media/video/cpia2/cpia2dev.h b/drivers/media/video/cpia2/cpia2dev.h new file mode 100644 index 00000000000..d58097ce0d5 --- /dev/null +++ b/drivers/media/video/cpia2/cpia2dev.h @@ -0,0 +1,50 @@ +/**************************************************************************** + * + * Filename: cpia2dev.h + * + * Copyright 2001, STMicrolectronics, Inc. + * + * Contact: steve.miller@st.com + * + * Description: + * This file provides definitions for applications wanting to use the + * cpia2 driver beyond the generic v4l capabilities. + * + * 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 CPIA2_DEV_HEADER +#define CPIA2_DEV_HEADER + +#include <linux/videodev.h> + +/*** + * The following defines are ioctl numbers based on video4linux private ioctls, + * which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int + * args + */ +#define CPIA2_IOC_SET_GPIO _IOW('v', BASE_VIDIOCPRIVATE + 17, __u32) + +/* V4L2 driver specific controls */ +#define CPIA2_CID_TARGET_KB (V4L2_CID_PRIVATE_BASE+0) +#define CPIA2_CID_GPIO (V4L2_CID_PRIVATE_BASE+1) +#define CPIA2_CID_FLICKER_MODE (V4L2_CID_PRIVATE_BASE+2) +#define CPIA2_CID_FRAMERATE (V4L2_CID_PRIVATE_BASE+3) +#define CPIA2_CID_USB_ALT (V4L2_CID_PRIVATE_BASE+4) +#define CPIA2_CID_LIGHTS (V4L2_CID_PRIVATE_BASE+5) +#define CPIA2_CID_RESET_CAMERA (V4L2_CID_PRIVATE_BASE+6) + +#endif diff --git a/drivers/media/video/cpia2/cpia2patch.h b/drivers/media/video/cpia2/cpia2patch.h new file mode 100644 index 00000000000..7f085fbe76f --- /dev/null +++ b/drivers/media/video/cpia2/cpia2patch.h @@ -0,0 +1,233 @@ +/**************************************************************************** + * + * Filename: cpia2patch.h + * + * Copyright 2001, STMicrolectronics, Inc. + * + * Contact: steve.miller@st.com + * + * Description: + * This file contains patch data for the CPiA2 (stv0672) VP4. + * + * 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 CPIA2_PATCH_HEADER +#define CPIA2_PATCH_HEADER + +typedef struct { + unsigned char reg; + unsigned char count; + const unsigned char *data; +} cpia2_patch; + +static const unsigned char start_address_hi[1] = { + 0x01 +}; + +static const unsigned char start_address_lo[1] = { + 0xBC +}; + +static const unsigned char patch_block0[64] = { + 0xE3, 0x02, 0xE3, 0x03, 0xE3, 0x04, 0xE3, 0x05, + 0xE3, 0x06, 0xE3, 0x07, 0x93, 0x44, 0x56, 0xD4, + 0x93, 0x4E, 0x56, 0x51, 0x93, 0x4E, 0x51, 0xD6, + 0x93, 0x4E, 0x4F, 0x54, 0x93, 0x4E, 0x92, 0x4F, + 0x92, 0xA4, 0x93, 0x05, 0x92, 0xF4, 0x93, 0x1B, + 0x92, 0x92, 0x91, 0xE6, 0x92, 0x36, 0x92, 0x74, + 0x92, 0x4A, 0x92, 0x8C, 0x92, 0x8E, 0xC8, 0xD0, + 0x0B, 0x42, 0x02, 0xA0, 0xCA, 0x92, 0x09, 0x02 +}; + +static const unsigned char patch_block1[64] = { + 0xC9, 0x10, 0x0A, 0x0A, 0x0A, 0x81, 0xE3, 0xB8, + 0xE3, 0xB0, 0xE3, 0xA8, 0xE3, 0xA0, 0xE3, 0x98, + 0xE3, 0x90, 0xE1, 0x00, 0xCF, 0xD7, 0x0A, 0x12, + 0xCC, 0x95, 0x08, 0xB2, 0x0A, 0x18, 0xE1, 0x00, + 0x01, 0xEE, 0x0C, 0x08, 0x4A, 0x12, 0xC8, 0x18, + 0xF0, 0x9A, 0xC0, 0x22, 0xF3, 0x1C, 0x4A, 0x13, + 0xF3, 0x14, 0xC8, 0xA0, 0xF2, 0x14, 0xF2, 0x1C, + 0xEB, 0x13, 0xD3, 0xA2, 0x63, 0x16, 0x48, 0x9E +}; + +static const unsigned char patch_block2[64] = { + 0xF0, 0x18, 0xA4, 0x03, 0xF3, 0x93, 0xC0, 0x58, + 0xF7, 0x13, 0x51, 0x9C, 0xE9, 0x20, 0xCF, 0xEF, + 0x63, 0xF9, 0x92, 0x2E, 0xD3, 0x5F, 0x63, 0xFA, + 0x92, 0x2E, 0xD3, 0x67, 0x63, 0xFB, 0x92, 0x2E, + 0xD3, 0x6F, 0xE9, 0x1A, 0x63, 0x16, 0x48, 0xA7, + 0xF0, 0x20, 0xA4, 0x06, 0xF3, 0x94, 0xC0, 0x27, + 0xF7, 0x14, 0xF5, 0x13, 0x51, 0x9D, 0xF6, 0x13, + 0x63, 0x18, 0xC4, 0x20, 0xCB, 0xEF, 0x63, 0xFC +}; + +static const unsigned char patch_block3[64] = { + 0x92, 0x2E, 0xD3, 0x77, 0x63, 0xFD, 0x92, 0x2E, + 0xD3, 0x7F, 0x63, 0xFE, 0x92, 0x2E, 0xD3, 0x87, + 0x63, 0xFF, 0x92, 0x2E, 0xD3, 0x8F, 0x64, 0x38, + 0x92, 0x2E, 0xD3, 0x97, 0x64, 0x39, 0x92, 0x2E, + 0xD3, 0x9F, 0xE1, 0x00, 0xF5, 0x3A, 0xF4, 0x3B, + 0xF7, 0xBF, 0xF2, 0xBC, 0xF2, 0x3D, 0xE1, 0x00, + 0x80, 0x87, 0x90, 0x80, 0x51, 0xD5, 0x02, 0x22, + 0x02, 0x32, 0x4B, 0xD3, 0xF7, 0x11, 0x0B, 0xDA +}; + +static const unsigned char patch_block4[64] = { + 0xE1, 0x00, 0x0E, 0x02, 0x02, 0x40, 0x0D, 0xB5, + 0xE3, 0x02, 0x48, 0x55, 0xE5, 0x12, 0xA4, 0x01, + 0xE8, 0x1B, 0xE3, 0x90, 0xF0, 0x18, 0xA4, 0x01, + 0xE8, 0xBF, 0x8D, 0xB8, 0x4B, 0xD1, 0x4B, 0xD8, + 0x0B, 0xCB, 0x0B, 0xC2, 0xE1, 0x00, 0xE3, 0x02, + 0xE3, 0x03, 0x52, 0xD3, 0x60, 0x59, 0xE6, 0x93, + 0x0D, 0x22, 0x52, 0xD4, 0xE6, 0x93, 0x0D, 0x2A, + 0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00, 0x02, 0x5D +}; + +static const unsigned char patch_block5[64] = { + 0x02, 0x63, 0xE3, 0x02, 0xC8, 0x12, 0x02, 0xCA, + 0xC8, 0x52, 0x02, 0xC2, 0x82, 0x68, 0xE3, 0x02, + 0xC8, 0x14, 0x02, 0xCA, 0xC8, 0x90, 0x02, 0xC2, + 0x0A, 0xD0, 0xC9, 0x93, 0x0A, 0xDA, 0xCC, 0xD2, + 0x0A, 0xE2, 0x63, 0x12, 0x02, 0xDA, 0x0A, 0x98, + 0x0A, 0xA0, 0x0A, 0xA8, 0xE3, 0x90, 0xE1, 0x00, + 0xE3, 0x02, 0x0A, 0xD0, 0xC9, 0x93, 0x0A, 0xDA, + 0xCC, 0xD2, 0x0A, 0xE2, 0x63, 0x12, 0x02, 0xDA +}; + +static const unsigned char patch_block6[64] = { + 0x0A, 0x98, 0x0A, 0xA0, 0x0A, 0xA8, 0x49, 0x91, + 0xE5, 0x6A, 0xA4, 0x04, 0xC8, 0x12, 0x02, 0xCA, + 0xC8, 0x52, 0x82, 0x89, 0xC8, 0x14, 0x02, 0xCA, + 0xC8, 0x90, 0x02, 0xC2, 0xE3, 0x90, 0xE1, 0x00, + 0x08, 0x60, 0xE1, 0x00, 0x48, 0x53, 0xE8, 0x97, + 0x08, 0x5A, 0xE1, 0x00, 0xE3, 0x02, 0xE3, 0x03, + 0x54, 0xD3, 0x60, 0x59, 0xE6, 0x93, 0x0D, 0x52, + 0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00, 0x02, 0x9C +}; + +static const unsigned char patch_block7[64] = { + 0xE3, 0x02, 0x55, 0x13, 0x93, 0x17, 0x55, 0x13, + 0x93, 0x17, 0xE3, 0x90, 0xE1, 0x00, 0x75, 0x30, + 0xE3, 0x02, 0xE3, 0x03, 0x55, 0x55, 0x60, 0x59, + 0xE6, 0x93, 0x0D, 0xB2, 0xE3, 0x98, 0xE3, 0x90, + 0xE1, 0x00, 0x02, 0xAE, 0xE7, 0x92, 0xE9, 0x18, + 0xEA, 0x9A, 0xE8, 0x98, 0xE8, 0x10, 0xE8, 0x11, + 0xE8, 0x51, 0xD2, 0xDA, 0xD2, 0xF3, 0xE8, 0x13, + 0xD2, 0xFA, 0xE8, 0x50, 0xD2, 0xEA, 0xE8, 0xD0 +}; + +static const unsigned char patch_block8[64] = { + 0xE8, 0xD1, 0xD3, 0x0A, 0x03, 0x09, 0x48, 0x23, + 0xE5, 0x2C, 0xA0, 0x03, 0x48, 0x24, 0xEA, 0x1C, + 0x03, 0x08, 0xD2, 0xE3, 0xD3, 0x03, 0xD3, 0x13, + 0xE1, 0x00, 0x02, 0xCB, 0x05, 0x93, 0x57, 0x93, + 0xF0, 0x9A, 0xAC, 0x0B, 0xE3, 0x07, 0x92, 0xEA, + 0xE2, 0x9F, 0xE5, 0x06, 0xE3, 0xB0, 0xA0, 0x02, + 0xEB, 0x1E, 0x82, 0xD7, 0xEA, 0x1E, 0xE2, 0x3B, + 0x85, 0x9B, 0xE9, 0x1E, 0xC8, 0x90, 0x85, 0x94 +}; + +static const unsigned char patch_block9[64] = { + 0x02, 0xDE, 0x05, 0x80, 0x57, 0x93, 0xF0, 0xBA, + 0xAC, 0x06, 0x92, 0xEA, 0xE2, 0xBF, 0xE5, 0x06, + 0xA0, 0x01, 0xEB, 0xBF, 0x85, 0x88, 0xE9, 0x3E, + 0xC8, 0x90, 0x85, 0x81, 0xE9, 0x3E, 0xF0, 0xBA, + 0xF3, 0x39, 0xF0, 0x3A, 0x60, 0x17, 0xF0, 0x3A, + 0xC0, 0x90, 0xF0, 0xBA, 0xE1, 0x00, 0x00, 0x3F, + 0xE3, 0x02, 0xE3, 0x03, 0x58, 0x10, 0x60, 0x59, + 0xE6, 0x93, 0x0D, 0xA2, 0x58, 0x12, 0xE6, 0x93 +}; + +static const unsigned char patch_block10[64] = { + 0x0D, 0xAA, 0xE3, 0x98, 0xE3, 0x90, 0xE1, 0x00, + 0x03, 0x01, 0xE1, 0x00, 0x03, 0x03, 0x9B, 0x7D, + 0x8B, 0x8B, 0xE3, 0x02, 0xE3, 0x03, 0x58, 0x56, + 0x60, 0x59, 0xE6, 0x93, 0x0D, 0xBA, 0xE3, 0x98, + 0xE3, 0x90, 0xE1, 0x00, 0x03, 0x0F, 0x93, 0x11, + 0xE1, 0x00, 0xE3, 0x02, 0x4A, 0x11, 0x0B, 0x42, + 0x91, 0xAF, 0xE3, 0x90, 0xE1, 0x00, 0xF2, 0x91, + 0xF0, 0x91, 0xA3, 0xFE, 0xE1, 0x00, 0x60, 0x92 +}; + +static const unsigned char patch_block11[64] = { + 0xC0, 0x5F, 0xF0, 0x13, 0xF0, 0x13, 0x59, 0x5B, + 0xE2, 0x13, 0xF0, 0x11, 0x5A, 0x19, 0xE2, 0x13, + 0xE1, 0x00, 0x00, 0x00, 0x03, 0x27, 0x68, 0x61, + 0x76, 0x61, 0x6E, 0x61, 0x00, 0x06, 0x03, 0x2C, + 0xE3, 0x02, 0xE3, 0x03, 0xE9, 0x38, 0x59, 0x15, + 0x59, 0x5A, 0xF2, 0x9A, 0xBC, 0x0B, 0xA4, 0x0A, + 0x59, 0x1E, 0xF3, 0x11, 0xF0, 0x1A, 0xE2, 0xBB, + 0x59, 0x15, 0xF0, 0x11, 0x19, 0x2A, 0xE5, 0x02 +}; + +static const unsigned char patch_block12[54] = { + 0xA4, 0x01, 0xEB, 0xBF, 0xE3, 0x98, 0xE3, 0x90, + 0xE1, 0x00, 0x03, 0x42, 0x19, 0x28, 0xE1, 0x00, + 0xE9, 0x30, 0x60, 0x79, 0xE1, 0x00, 0xE3, 0x03, + 0xE3, 0x07, 0x60, 0x79, 0x93, 0x4E, 0xE3, 0xB8, + 0xE3, 0x98, 0xE1, 0x00, 0xE9, 0x1A, 0xF0, 0x1F, + 0xE2, 0x33, 0xF0, 0x91, 0xE2, 0x92, 0xE0, 0x32, + 0xF0, 0x31, 0xE1, 0x00, 0x00, 0x00 +}; + +static const unsigned char do_call[1] = { + 0x01 +}; + + +#define PATCH_DATA_SIZE 18 + +static const cpia2_patch patch_data[PATCH_DATA_SIZE] = { + {0x0A, sizeof(start_address_hi), start_address_hi} + , // 0 + {0x0B, sizeof(start_address_lo), start_address_lo} + , // 1 + {0x0C, sizeof(patch_block0), patch_block0} + , // 2 + {0x0C, sizeof(patch_block1), patch_block1} + , // 3 + {0x0C, sizeof(patch_block2), patch_block2} + , // 4 + {0x0C, sizeof(patch_block3), patch_block3} + , // 5 + {0x0C, sizeof(patch_block4), patch_block4} + , // 6 + {0x0C, sizeof(patch_block5), patch_block5} + , // 7 + {0x0C, sizeof(patch_block6), patch_block6} + , // 8 + {0x0C, sizeof(patch_block7), patch_block7} + , // 9 + {0x0C, sizeof(patch_block8), patch_block8} + , // 10 + {0x0C, sizeof(patch_block9), patch_block9} + , //11 + {0x0C, sizeof(patch_block10), patch_block10} + , // 12 + {0x0C, sizeof(patch_block11), patch_block11} + , // 13 + {0x0C, sizeof(patch_block12), patch_block12} + , // 14 + {0x0A, sizeof(start_address_hi), start_address_hi} + , // 15 + {0x0B, sizeof(start_address_lo), start_address_lo} + , // 16 + {0x0D, sizeof(do_call), do_call} //17 +}; + + +#endif diff --git a/drivers/media/video/cx25840/Kconfig b/drivers/media/video/cx25840/Kconfig new file mode 100644 index 00000000000..854264e42ec --- /dev/null +++ b/drivers/media/video/cx25840/Kconfig @@ -0,0 +1,9 @@ +config VIDEO_CX25840 + tristate "Conexant CX2584x audio/video decoders" + depends on VIDEO_DEV && I2C && EXPERIMENTAL + select FW_LOADER + ---help--- + Support for the Conexant CX2584x audio/video decoders. + + To compile this driver as a module, choose M here: the + module will be called cx25840 diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile index 543ebacdc9d..32a896c23d1 100644 --- a/drivers/media/video/cx25840/Makefile +++ b/drivers/media/video/cx25840/Makefile @@ -1,6 +1,6 @@ cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \ cx25840-vbi.o -obj-$(CONFIG_VIDEO_DECODER) += cx25840.o +obj-$(CONFIG_VIDEO_CX25840) += cx25840.o EXTRA_CFLAGS += -I$(src)/.. diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c index 5588b9a5c43..8a257978056 100644 --- a/drivers/media/video/cx25840/cx25840-core.c +++ b/drivers/media/video/cx25840/cx25840-core.c @@ -743,6 +743,7 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, memset(input, 0, sizeof(*input)); input->index = state->aud_input; + input->capability = V4L2_AUDCAP_STEREO; break; } @@ -753,7 +754,6 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, case VIDIOC_G_TUNER: { u8 mode = cx25840_read(client, 0x804); - u8 pref = cx25840_read(client, 0x809) & 0xf; u8 vpres = cx25840_read(client, 0x80a) & 0x10; int val = 0; @@ -773,44 +773,49 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd, val |= V4L2_TUNER_SUB_MONO; if (mode == 2 || mode == 4) - val |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; if (mode & 0x10) val |= V4L2_TUNER_SUB_SAP; vt->rxsubchans = val; - - switch (pref) { - case 0: - vt->audmode = V4L2_TUNER_MODE_MONO; - break; - case 1: - case 2: - vt->audmode = V4L2_TUNER_MODE_LANG2; - break; - case 4: - default: - vt->audmode = V4L2_TUNER_MODE_STEREO; - } + vt->audmode = state->audmode; break; } case VIDIOC_S_TUNER: + if (state->radio) + break; + switch (vt->audmode) { case V4L2_TUNER_MODE_MONO: - case V4L2_TUNER_MODE_LANG1: - /* Force PREF_MODE to MONO */ + /* mono -> mono + stereo -> mono + bilingual -> lang1 */ cx25840_and_or(client, 0x809, ~0xf, 0x00); break; - case V4L2_TUNER_MODE_STEREO: - /* Force PREF_MODE to STEREO */ + case V4L2_TUNER_MODE_LANG1: + /* mono -> mono + stereo -> stereo + bilingual -> lang1 */ cx25840_and_or(client, 0x809, ~0xf, 0x04); break; + case V4L2_TUNER_MODE_STEREO: + /* mono -> mono + stereo -> stereo + bilingual -> lang1/lang2 */ + cx25840_and_or(client, 0x809, ~0xf, 0x07); + break; case V4L2_TUNER_MODE_LANG2: - /* Force PREF_MODE to LANG2 */ + /* mono -> mono + stereo ->stereo + bilingual -> lang2 */ cx25840_and_or(client, 0x809, ~0xf, 0x01); break; + default: + return -EINVAL; } + state->audmode = vt->audmode; break; case VIDIOC_G_FMT: @@ -891,6 +896,7 @@ static int cx25840_detect_client(struct i2c_adapter *adapter, int address, state->aud_input = CX25840_AUDIO8; state->audclk_freq = 48000; state->pvr150_workaround = 0; + state->audmode = V4L2_TUNER_MODE_LANG1; cx25840_initialize(client, 1); diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c index 04d879da7d6..e96fd1f1d6d 100644 --- a/drivers/media/video/cx25840/cx25840-vbi.c +++ b/drivers/media/video/cx25840/cx25840-vbi.c @@ -151,7 +151,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOC_G_FMT: { static u16 lcr2vbi[] = { - 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ + 0, V4L2_SLICED_TELETEXT_PAL_B, 0, /* 1 */ 0, V4L2_SLICED_WSS_625, 0, /* 4 */ V4L2_SLICED_CAPTION_525, /* 6 */ 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */ @@ -231,7 +231,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) for (i = 7; i <= 23; i++) { for (x = 0; x <= 1; x++) { switch (svbi->service_lines[1-x][i]) { - case V4L2_SLICED_TELETEXT_B: + case V4L2_SLICED_TELETEXT_PAL_B: lcr[i] |= 1 << (4 * x); break; case V4L2_SLICED_WSS_625: @@ -282,7 +282,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg) switch (id2) { case 1: - id2 = V4L2_SLICED_TELETEXT_B; + id2 = V4L2_SLICED_TELETEXT_PAL_B; break; case 4: id2 = V4L2_SLICED_WSS_625; diff --git a/drivers/media/video/cx25840/cx25840.h b/drivers/media/video/cx25840/cx25840.h index fd22f30dcc1..dd70664d1dd 100644 --- a/drivers/media/video/cx25840/cx25840.h +++ b/drivers/media/video/cx25840/cx25840.h @@ -78,6 +78,7 @@ struct cx25840_state { enum cx25840_video_input vid_input; enum cx25840_audio_input aud_input; u32 audclk_freq; + int audmode; }; /* ----------------------------------------------------------------------- */ diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig index e99dfbbf3e9..e140996e6ee 100644 --- a/drivers/media/video/cx88/Kconfig +++ b/drivers/media/video/cx88/Kconfig @@ -15,20 +15,6 @@ config VIDEO_CX88 To compile this driver as a module, choose M here: the module will be called cx8800 -config VIDEO_CX88_DVB - tristate "DVB/ATSC Support for cx2388x based TV cards" - depends on VIDEO_CX88 && DVB_CORE - select VIDEO_BUF_DVB - ---help--- - This adds support for DVB/ATSC cards based on the - Connexant 2388x chip. - - To compile this driver as a module, choose M here: the - module will be called cx88-dvb. - - You must also select one or more DVB/ATSC demodulators. - If you are unsure which you need, choose all of them. - config VIDEO_CX88_ALSA tristate "ALSA DMA audio support" depends on VIDEO_CX88 && SND && EXPERIMENTAL @@ -44,12 +30,27 @@ config VIDEO_CX88_ALSA To compile this driver as a module, choose M here: the module will be called cx88-alsa. +config VIDEO_CX88_DVB + tristate "DVB/ATSC Support for cx2388x based TV cards" + depends on VIDEO_CX88 && DVB_CORE + select VIDEO_BUF_DVB + ---help--- + This adds support for DVB/ATSC cards based on the + Connexant 2388x chip. + + To compile this driver as a module, choose M here: the + module will be called cx88-dvb. + + You must also select one or more DVB/ATSC demodulators. + If you are unsure which you need, choose all of them. + config VIDEO_CX88_DVB_ALL_FRONTENDS bool "Build all supported frontends for cx2388x based TV cards" default y depends on VIDEO_CX88_DVB select DVB_MT352 select VIDEO_CX88_VP3054 + select DVB_ZL10353 select DVB_OR51132 select DVB_CX22702 select DVB_LGDT330X @@ -81,6 +82,16 @@ config VIDEO_CX88_VP3054 which also require support for the VP-3054 Secondary I2C bus, such at DNTV Live! DVB-T Pro. +config VIDEO_CX88_DVB_ZL10353 + bool "Zarlink ZL10353 DVB-T Support" + default y + depends on VIDEO_CX88_DVB && !VIDEO_CX88_DVB_ALL_FRONTENDS + select DVB_ZL10353 + ---help--- + This adds DVB-T support for cards based on the + Connexant 2388x chip and the ZL10353 demodulator, + successor to the Zarlink MT352. + config VIDEO_CX88_DVB_OR51132 bool "OR51132 ATSC Support" default y diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index 2b902784fac..6482b9aa6a1 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile @@ -17,6 +17,7 @@ extra-cflags-$(CONFIG_DVB_CX22702) += -DHAVE_CX22702=1 extra-cflags-$(CONFIG_DVB_OR51132) += -DHAVE_OR51132=1 extra-cflags-$(CONFIG_DVB_LGDT330X) += -DHAVE_LGDT330X=1 extra-cflags-$(CONFIG_DVB_MT352) += -DHAVE_MT352=1 +extra-cflags-$(CONFIG_DVB_ZL10353) += -DHAVE_ZL10353=1 extra-cflags-$(CONFIG_DVB_NXT200X) += -DHAVE_NXT200X=1 extra-cflags-$(CONFIG_DVB_CX24123) += -DHAVE_CX24123=1 extra-cflags-$(CONFIG_VIDEO_CX88_VP3054)+= -DHAVE_VP3054_I2C=1 diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 2acccd6d49b..bffef1decc8 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -672,6 +672,11 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci, chip = (snd_cx88_card_t *) card->private_data; core = cx88_core_get(pci); + if (NULL == core) { + err = -EINVAL; + kfree (chip); + return err; + } if (!pci_dma_supported(pci,0xffffffff)) { dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); @@ -688,11 +693,6 @@ static int __devinit snd_cx88_create(snd_card_t *card, struct pci_dev *pci, spin_lock_init(&chip->reg_lock); cx88_reset(core); - if (NULL == core) { - err = -EINVAL; - kfree (chip); - return err; - } chip->core = core; /* get irq */ diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index 1bc999247fd..c7042cf4123 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -184,17 +184,18 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio1 = 0x309f, + .gpio1 = 0xe09f, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - .gpio1 = 0x305f, + .gpio1 = 0xe05f, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, - .gpio1 = 0x305f, + .gpio1 = 0xe05f, }}, .radio = { + .gpio1 = 0xe0df, .type = CX88_RADIO, }, }, @@ -322,19 +323,19 @@ struct cx88_board cx88_boards[] = { .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, - .gpio0 = 0xff00, + .gpio0 = 0xbff0, },{ .type = CX88_VMUX_COMPOSITE1, .vmux = 1, - .gpio0 = 0xff03, + .gpio0 = 0xbff3, },{ .type = CX88_VMUX_SVIDEO, .vmux = 2, - .gpio0 = 0xff03, + .gpio0 = 0xbff3, }}, .radio = { .type = CX88_RADIO, - .gpio0 = 0xff00, + .gpio0 = 0xbff0, }, }, [CX88_BOARD_ASUS_PVR_416] = { @@ -1048,6 +1049,50 @@ struct cx88_board cx88_boards[] = { }}, .dvb = 1, }, + [CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT] = { + /* FIXME: Standard video using the cx88 broadcast decoder is + * working, but blackbird isn't working yet, audio is only + * working correctly for television mode. S-Video and Composite + * are working for video-only, so I have them disabled for now. + */ + .name = "KWorld HardwareMpegTV XPert", + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x3de2, + .gpio2 = 0x00ff, + }}, + .radio = { + .type = CX88_RADIO, + .gpio0 = 0x3de6, + .gpio2 = 0x00ff, + }, + }, + [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID] = { + .name = "DViCO FusionHDTV DVB-T Hybrid", + .tuner_type = TUNER_THOMSON_FE6600, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .input = {{ + .type = CX88_VMUX_TELEVISION, + .vmux = 0, + .gpio0 = 0x0000a75f, + },{ + .type = CX88_VMUX_COMPOSITE1, + .vmux = 1, + .gpio0 = 0x0000a75b, + },{ + .type = CX88_VMUX_SVIDEO, + .vmux = 2, + .gpio0 = 0x0000a75b, + }}, + .dvb = 1, + }, }; const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards); @@ -1254,6 +1299,18 @@ struct cx88_subid cx88_subids[] = { .subdevice = 0xdb11, .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS, /* Re-branded DViCO: UltraView DVB-T Plus */ + },{ + .subvendor = 0x17de, + .subdevice = 0x0840, + .card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT, + },{ + .subvendor = 0x18ac, + .subdevice = 0xdb40, + .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID, + },{ + .subvendor = 0x18ac, + .subdevice = 0xdb44, + .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID, }, }; const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids); @@ -1373,6 +1430,40 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data) } /* ----------------------------------------------------------------------- */ +/* some DViCO specific stuff */ + +static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) +{ + struct i2c_msg msg = { .addr = 0x45, .flags = 0 }; + int i, err; + static u8 init_bufs[13][5] = { + { 0x10, 0x00, 0x20, 0x01, 0x03 }, + { 0x10, 0x10, 0x01, 0x00, 0x21 }, + { 0x10, 0x10, 0x10, 0x00, 0xCA }, + { 0x10, 0x10, 0x12, 0x00, 0x08 }, + { 0x10, 0x10, 0x13, 0x00, 0x0A }, + { 0x10, 0x10, 0x16, 0x01, 0xC0 }, + { 0x10, 0x10, 0x22, 0x01, 0x3D }, + { 0x10, 0x10, 0x73, 0x01, 0x2E }, + { 0x10, 0x10, 0x72, 0x00, 0xC5 }, + { 0x10, 0x10, 0x71, 0x01, 0x97 }, + { 0x10, 0x10, 0x70, 0x00, 0x0F }, + { 0x10, 0x10, 0xB0, 0x00, 0x01 }, + { 0x03, 0x0C }, + }; + + for (i = 0; i < 13; i++) { + msg.buf = init_bufs[i]; + msg.len = (i != 12 ? 5 : 2); + err = i2c_transfer(&core->i2c_adap, &msg, 1); + if (err != 1) { + printk("dvico_fusionhdtv_hybrid_init buf %d failed (err = %d)!\n", i, err); + return; + } + } +} + +/* ----------------------------------------------------------------------- */ void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) { @@ -1438,11 +1529,15 @@ void cx88_card_setup(struct cx88_core *core) case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL: + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: /* GPIO0:0 is hooked to mt352 reset pin */ cx_set(MO_GP0_IO, 0x00000101); cx_clear(MO_GP0_IO, 0x00000001); msleep(1); cx_set(MO_GP0_IO, 0x00000101); + if (0 == core->i2c_rc && + core->board == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) + dvico_fusionhdtv_hybrid_init(core); break; case CX88_BOARD_KWORLD_DVB_T: case CX88_BOARD_DNTV_LIVE_DVB_T: @@ -1460,7 +1555,7 @@ void cx88_card_setup(struct cx88_core *core) if (0 == core->i2c_rc) { /* enable tuner */ int i; - u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 }; + static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 }; core->i2c_client.addr = 0x0a; for (i = 0; i < 5; i++) diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index 3720f24a25c..c2cdbafdb77 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -163,7 +163,7 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* save pointer to jmp instruction address */ risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size); + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); return 0; } @@ -188,7 +188,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc, /* save pointer to jmp instruction address */ risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) / 4 > risc->size); + BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); return 0; } @@ -215,8 +215,7 @@ int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc, void cx88_free_buffer(struct pci_dev *pci, struct cx88_buffer *buf) { - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); videobuf_dma_pci_unmap(pci, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); @@ -1061,7 +1060,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) core->pci_bus = pci->bus->number; core->pci_slot = PCI_SLOT(pci->devfn); core->pci_irqmask = 0x00fc00; - init_MUTEX(&core->lock); + mutex_init(&core->lock); core->nr = cx88_devcount++; sprintf(core->name,"cx88[%d]",core->nr); diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c index e48aa3f6e50..a9fc2695b15 100644 --- a/drivers/media/video/cx88/cx88-dvb.c +++ b/drivers/media/video/cx88/cx88-dvb.c @@ -40,6 +40,9 @@ # include "cx88-vp3054-i2c.h" # endif #endif +#ifdef HAVE_ZL10353 +# include "zl10353.h" +#endif #ifdef HAVE_CX22702 # include "cx22702.h" #endif @@ -111,6 +114,21 @@ static struct videobuf_queue_ops dvb_qops = { /* ------------------------------------------------------------------ */ +#if defined(HAVE_MT352) || defined(HAVE_ZL10353) +static int zarlink_pll_set(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, + u8 *pllbuf) +{ + struct cx8802_dev *dev = fe->dvb->priv; + + pllbuf[0] = dev->core->pll_addr << 1; + dvb_pll_configure(dev->core->pll_desc, pllbuf + 1, + params->frequency, + params->u.ofdm.bandwidth); + return 0; +} +#endif + #ifdef HAVE_MT352 static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe) { @@ -176,35 +194,22 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe) return 0; } -static int mt352_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params, - u8* pllbuf) -{ - struct cx8802_dev *dev= fe->dvb->priv; - - pllbuf[0] = dev->core->pll_addr << 1; - dvb_pll_configure(dev->core->pll_desc, pllbuf+1, - params->frequency, - params->u.ofdm.bandwidth); - return 0; -} - static struct mt352_config dvico_fusionhdtv = { .demod_address = 0x0F, .demod_init = dvico_fusionhdtv_demod_init, - .pll_set = mt352_pll_set, + .pll_set = zarlink_pll_set, }; static struct mt352_config dntv_live_dvbt_config = { .demod_address = 0x0f, .demod_init = dntv_live_dvbt_demod_init, - .pll_set = mt352_pll_set, + .pll_set = zarlink_pll_set, }; static struct mt352_config dvico_fusionhdtv_dual = { .demod_address = 0x0F, .demod_init = dvico_dual_demod_init, - .pll_set = mt352_pll_set, + .pll_set = zarlink_pll_set, }; #ifdef HAVE_VP3054_I2C @@ -294,6 +299,46 @@ static struct mt352_config dntv_live_dvbt_pro_config = { #endif #endif +#ifdef HAVE_ZL10353 +static int dvico_hybrid_tune_pll(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params, + u8 *pllbuf) +{ + struct cx8802_dev *dev= fe->dvb->priv; + struct i2c_msg msg = + { .addr = dev->core->pll_addr, .flags = 0, + .buf = pllbuf + 1, .len = 4 }; + int err; + + pllbuf[0] = dev->core->pll_addr << 1; + dvb_pll_configure(dev->core->pll_desc, pllbuf + 1, + params->frequency, + params->u.ofdm.bandwidth); + + if ((err = i2c_transfer(&dev->core->i2c_adap, &msg, 1)) != 1) { + printk(KERN_WARNING "cx88-dvb: %s error " + "(addr %02x <- %02x, err = %i)\n", + __FUNCTION__, pllbuf[0], pllbuf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + + return 0; +} + +static struct zl10353_config dvico_fusionhdtv_hybrid = { + .demod_address = 0x0F, + .pll_set = dvico_hybrid_tune_pll, +}; + +static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = { + .demod_address = 0x0F, + .pll_set = zarlink_pll_set, +}; +#endif + #ifdef HAVE_CX22702 static struct cx22702_config connexant_refboard_config = { .demod_address = 0x43, @@ -500,16 +545,27 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); break; #endif +#if defined(HAVE_MT352) || defined(HAVE_ZL10353) + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: + dev->core->pll_addr = 0x60; + dev->core->pll_desc = &dvb_pll_thomson_dtt7579; #ifdef HAVE_MT352 - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: - dev->core->pll_addr = 0x61; - dev->core->pll_desc = &dvb_pll_lg_z201; dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv, &dev->core->i2c_adap); + if (dev->dvb.frontend != NULL) + break; +#endif +#ifdef HAVE_ZL10353 + /* ZL10353 replaces MT352 on later cards */ + dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_plus_v1_1, + &dev->core->i2c_adap); +#endif break; - case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS: - dev->core->pll_addr = 0x60; - dev->core->pll_desc = &dvb_pll_thomson_dtt7579; +#endif /* HAVE_MT352 || HAVE_ZL10353 */ +#ifdef HAVE_MT352 + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1: + dev->core->pll_addr = 0x61; + dev->core->pll_desc = &dvb_pll_lg_z201; dev->dvb.frontend = mt352_attach(&dvico_fusionhdtv, &dev->core->i2c_adap); break; @@ -540,6 +596,14 @@ static int dvb_register(struct cx8802_dev *dev) &dev->core->i2c_adap); break; #endif +#ifdef HAVE_ZL10353 + case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: + dev->core->pll_addr = 0x61; + dev->core->pll_desc = &dvb_pll_thomson_fe6600; + dev->dvb.frontend = zl10353_attach(&dvico_fusionhdtv_hybrid, + &dev->core->i2c_adap); + break; +#endif #ifdef HAVE_OR51132 case CX88_BOARD_PCHDTV_HD3000: dev->dvb.frontend = or51132_attach(&pchdtv_hd3000, diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c index 165d948624a..78a63b7dd38 100644 --- a/drivers/media/video/cx88/cx88-input.c +++ b/drivers/media/video/cx88/cx88-input.c @@ -34,337 +34,6 @@ /* ---------------------------------------------------------------------- */ -/* DigitalNow DNTV Live DVB-T Remote */ -static IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = { - [0x00] = KEY_ESC, /* 'go up a level?' */ - /* Keys 0 to 9 */ - [0x0a] = KEY_KP0, - [0x01] = KEY_KP1, - [0x02] = KEY_KP2, - [0x03] = KEY_KP3, - [0x04] = KEY_KP4, - [0x05] = KEY_KP5, - [0x06] = KEY_KP6, - [0x07] = KEY_KP7, - [0x08] = KEY_KP8, - [0x09] = KEY_KP9, - - [0x0b] = KEY_TUNER, /* tv/fm */ - [0x0c] = KEY_SEARCH, /* scan */ - [0x0d] = KEY_STOP, - [0x0e] = KEY_PAUSE, - [0x0f] = KEY_LIST, /* source */ - - [0x10] = KEY_MUTE, - [0x11] = KEY_REWIND, /* backward << */ - [0x12] = KEY_POWER, - [0x13] = KEY_S, /* snap */ - [0x14] = KEY_AUDIO, /* stereo */ - [0x15] = KEY_CLEAR, /* reset */ - [0x16] = KEY_PLAY, - [0x17] = KEY_ENTER, - [0x18] = KEY_ZOOM, /* full screen */ - [0x19] = KEY_FASTFORWARD, /* forward >> */ - [0x1a] = KEY_CHANNELUP, - [0x1b] = KEY_VOLUMEUP, - [0x1c] = KEY_INFO, /* preview */ - [0x1d] = KEY_RECORD, /* record */ - [0x1e] = KEY_CHANNELDOWN, - [0x1f] = KEY_VOLUMEDOWN, -}; - -/* ---------------------------------------------------------------------- */ - -/* IO-DATA BCTV7E Remote */ -static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = { - [0x40] = KEY_TV, - [0x20] = KEY_RADIO, /* FM */ - [0x60] = KEY_EPG, - [0x00] = KEY_POWER, - - /* Keys 0 to 9 */ - [0x44] = KEY_KP0, /* 10 */ - [0x50] = KEY_KP1, - [0x30] = KEY_KP2, - [0x70] = KEY_KP3, - [0x48] = KEY_KP4, - [0x28] = KEY_KP5, - [0x68] = KEY_KP6, - [0x58] = KEY_KP7, - [0x38] = KEY_KP8, - [0x78] = KEY_KP9, - - [0x10] = KEY_L, /* Live */ - [0x08] = KEY_T, /* Time Shift */ - - [0x18] = KEY_PLAYPAUSE, /* Play */ - - [0x24] = KEY_ENTER, /* 11 */ - [0x64] = KEY_ESC, /* 12 */ - [0x04] = KEY_M, /* Multi */ - - [0x54] = KEY_VIDEO, - [0x34] = KEY_CHANNELUP, - [0x74] = KEY_VOLUMEUP, - [0x14] = KEY_MUTE, - - [0x4c] = KEY_S, /* SVIDEO */ - [0x2c] = KEY_CHANNELDOWN, - [0x6c] = KEY_VOLUMEDOWN, - [0x0c] = KEY_ZOOM, - - [0x5c] = KEY_PAUSE, - [0x3c] = KEY_C, /* || (red) */ - [0x7c] = KEY_RECORD, /* recording */ - [0x1c] = KEY_STOP, - - [0x41] = KEY_REWIND, /* backward << */ - [0x21] = KEY_PLAY, - [0x61] = KEY_FASTFORWARD, /* forward >> */ - [0x01] = KEY_NEXT, /* skip >| */ -}; - -/* ---------------------------------------------------------------------- */ - -/* ADS Tech Instant TV DVB-T PCI Remote */ -static IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = { - /* Keys 0 to 9 */ - [0x4d] = KEY_0, - [0x57] = KEY_1, - [0x4f] = KEY_2, - [0x53] = KEY_3, - [0x56] = KEY_4, - [0x4e] = KEY_5, - [0x5e] = KEY_6, - [0x54] = KEY_7, - [0x4c] = KEY_8, - [0x5c] = KEY_9, - - [0x5b] = KEY_POWER, - [0x5f] = KEY_MUTE, - [0x55] = KEY_GOTO, - [0x5d] = KEY_SEARCH, - [0x17] = KEY_EPG, /* Guide */ - [0x1f] = KEY_MENU, - [0x0f] = KEY_UP, - [0x46] = KEY_DOWN, - [0x16] = KEY_LEFT, - [0x1e] = KEY_RIGHT, - [0x0e] = KEY_SELECT, /* Enter */ - [0x5a] = KEY_INFO, - [0x52] = KEY_EXIT, - [0x59] = KEY_PREVIOUS, - [0x51] = KEY_NEXT, - [0x58] = KEY_REWIND, - [0x50] = KEY_FORWARD, - [0x44] = KEY_PLAYPAUSE, - [0x07] = KEY_STOP, - [0x1b] = KEY_RECORD, - [0x13] = KEY_TUNER, /* Live */ - [0x0a] = KEY_A, - [0x12] = KEY_B, - [0x03] = KEY_PROG1, /* 1 */ - [0x01] = KEY_PROG2, /* 2 */ - [0x00] = KEY_PROG3, /* 3 */ - [0x06] = KEY_DVD, - [0x48] = KEY_AUX, /* Photo */ - [0x40] = KEY_VIDEO, - [0x19] = KEY_AUDIO, /* Music */ - [0x0b] = KEY_CHANNELUP, - [0x08] = KEY_CHANNELDOWN, - [0x15] = KEY_VOLUMEUP, - [0x1c] = KEY_VOLUMEDOWN, -}; - -/* ---------------------------------------------------------------------- */ - -/* MSI TV@nywhere remote */ -static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = { - /* Keys 0 to 9 */ - [0x00] = KEY_0, - [0x01] = KEY_1, - [0x02] = KEY_2, - [0x03] = KEY_3, - [0x04] = KEY_4, - [0x05] = KEY_5, - [0x06] = KEY_6, - [0x07] = KEY_7, - [0x08] = KEY_8, - [0x09] = KEY_9, - - [0x0c] = KEY_MUTE, - [0x0f] = KEY_SCREEN, /* Full Screen */ - [0x10] = KEY_F, /* Funtion */ - [0x11] = KEY_T, /* Time shift */ - [0x12] = KEY_POWER, - [0x13] = KEY_MEDIA, /* MTS */ - [0x14] = KEY_SLOW, - [0x16] = KEY_REWIND, /* backward << */ - [0x17] = KEY_ENTER, /* Return */ - [0x18] = KEY_FASTFORWARD, /* forward >> */ - [0x1a] = KEY_CHANNELUP, - [0x1b] = KEY_VOLUMEUP, - [0x1e] = KEY_CHANNELDOWN, - [0x1f] = KEY_VOLUMEDOWN, -}; - -/* ---------------------------------------------------------------------- */ - -/* Cinergy 1400 DVB-T */ -static IR_KEYTAB_TYPE ir_codes_cinergy_1400[IR_KEYTAB_SIZE] = { - [0x01] = KEY_POWER, - [0x02] = KEY_1, - [0x03] = KEY_2, - [0x04] = KEY_3, - [0x05] = KEY_4, - [0x06] = KEY_5, - [0x07] = KEY_6, - [0x08] = KEY_7, - [0x09] = KEY_8, - [0x0a] = KEY_9, - [0x0c] = KEY_0, - - [0x0b] = KEY_VIDEO, - [0x0d] = KEY_REFRESH, - [0x0e] = KEY_SELECT, - [0x0f] = KEY_EPG, - [0x10] = KEY_UP, - [0x11] = KEY_LEFT, - [0x12] = KEY_OK, - [0x13] = KEY_RIGHT, - [0x14] = KEY_DOWN, - [0x15] = KEY_TEXT, - [0x16] = KEY_INFO, - - [0x17] = KEY_RED, - [0x18] = KEY_GREEN, - [0x19] = KEY_YELLOW, - [0x1a] = KEY_BLUE, - - [0x1b] = KEY_CHANNELUP, - [0x1c] = KEY_VOLUMEUP, - [0x1d] = KEY_MUTE, - [0x1e] = KEY_VOLUMEDOWN, - [0x1f] = KEY_CHANNELDOWN, - - [0x40] = KEY_PAUSE, - [0x4c] = KEY_PLAY, - [0x58] = KEY_RECORD, - [0x54] = KEY_PREVIOUS, - [0x48] = KEY_STOP, - [0x5c] = KEY_NEXT, -}; - -/* ---------------------------------------------------------------------- */ - -/* AVERTV STUDIO 303 Remote */ -static IR_KEYTAB_TYPE ir_codes_avertv_303[IR_KEYTAB_SIZE] = { - [ 0x2a ] = KEY_KP1, - [ 0x32 ] = KEY_KP2, - [ 0x3a ] = KEY_KP3, - [ 0x4a ] = KEY_KP4, - [ 0x52 ] = KEY_KP5, - [ 0x5a ] = KEY_KP6, - [ 0x6a ] = KEY_KP7, - [ 0x72 ] = KEY_KP8, - [ 0x7a ] = KEY_KP9, - [ 0x0e ] = KEY_KP0, - - [ 0x02 ] = KEY_POWER, - [ 0x22 ] = KEY_VIDEO, - [ 0x42 ] = KEY_AUDIO, - [ 0x62 ] = KEY_ZOOM, - [ 0x0a ] = KEY_TV, - [ 0x12 ] = KEY_CD, - [ 0x1a ] = KEY_TEXT, - - [ 0x16 ] = KEY_SUBTITLE, - [ 0x1e ] = KEY_REWIND, - [ 0x06 ] = KEY_PRINT, - - [ 0x2e ] = KEY_SEARCH, - [ 0x36 ] = KEY_SLEEP, - [ 0x3e ] = KEY_SHUFFLE, - [ 0x26 ] = KEY_MUTE, - - [ 0x4e ] = KEY_RECORD, - [ 0x56 ] = KEY_PAUSE, - [ 0x5e ] = KEY_STOP, - [ 0x46 ] = KEY_PLAY, - - [ 0x6e ] = KEY_RED, - [ 0x0b ] = KEY_GREEN, - [ 0x66 ] = KEY_YELLOW, - [ 0x03 ] = KEY_BLUE, - - [ 0x76 ] = KEY_LEFT, - [ 0x7e ] = KEY_RIGHT, - [ 0x13 ] = KEY_DOWN, - [ 0x1b ] = KEY_UP, -}; - -/* ---------------------------------------------------------------------- */ - -/* DigitalNow DNTV Live! DVB-T Pro Remote */ -static IR_KEYTAB_TYPE ir_codes_dntv_live_dvbt_pro[IR_KEYTAB_SIZE] = { - [ 0x16 ] = KEY_POWER, - [ 0x5b ] = KEY_HOME, - - [ 0x55 ] = KEY_TV, /* live tv */ - [ 0x58 ] = KEY_TUNER, /* digital Radio */ - [ 0x5a ] = KEY_RADIO, /* FM radio */ - [ 0x59 ] = KEY_DVD, /* dvd menu */ - [ 0x03 ] = KEY_1, - [ 0x01 ] = KEY_2, - [ 0x06 ] = KEY_3, - [ 0x09 ] = KEY_4, - [ 0x1d ] = KEY_5, - [ 0x1f ] = KEY_6, - [ 0x0d ] = KEY_7, - [ 0x19 ] = KEY_8, - [ 0x1b ] = KEY_9, - [ 0x0c ] = KEY_CANCEL, - [ 0x15 ] = KEY_0, - [ 0x4a ] = KEY_CLEAR, - [ 0x13 ] = KEY_BACK, - [ 0x00 ] = KEY_TAB, - [ 0x4b ] = KEY_UP, - [ 0x4e ] = KEY_LEFT, - [ 0x4f ] = KEY_OK, - [ 0x52 ] = KEY_RIGHT, - [ 0x51 ] = KEY_DOWN, - [ 0x1e ] = KEY_VOLUMEUP, - [ 0x0a ] = KEY_VOLUMEDOWN, - [ 0x02 ] = KEY_CHANNELDOWN, - [ 0x05 ] = KEY_CHANNELUP, - [ 0x11 ] = KEY_RECORD, - [ 0x14 ] = KEY_PLAY, - [ 0x4c ] = KEY_PAUSE, - [ 0x1a ] = KEY_STOP, - [ 0x40 ] = KEY_REWIND, - [ 0x12 ] = KEY_FASTFORWARD, - [ 0x41 ] = KEY_PREVIOUSSONG, /* replay |< */ - [ 0x42 ] = KEY_NEXTSONG, /* skip >| */ - [ 0x54 ] = KEY_CAMERA, /* capture */ - [ 0x50 ] = KEY_LANGUAGE, /* sap */ - [ 0x47 ] = KEY_TV2, /* pip */ - [ 0x4d ] = KEY_SCREEN, - [ 0x43 ] = KEY_SUBTITLE, - [ 0x10 ] = KEY_MUTE, - [ 0x49 ] = KEY_AUDIO, /* l/r */ - [ 0x07 ] = KEY_SLEEP, - [ 0x08 ] = KEY_VIDEO, /* a/v */ - [ 0x0e ] = KEY_PREVIOUS, /* recall */ - [ 0x45 ] = KEY_ZOOM, /* zoom + */ - [ 0x46 ] = KEY_ANGLE, /* zoom - */ - [ 0x56 ] = KEY_RED, - [ 0x57 ] = KEY_GREEN, - [ 0x5c ] = KEY_YELLOW, - [ 0x5d ] = KEY_BLUE, -}; - -/* ---------------------------------------------------------------------- */ - struct cx88_IR { struct cx88_core *core; struct input_dev *input; @@ -517,6 +186,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keydown = 0x02; ir->polling = 5; /* ms */ break; + case CX88_BOARD_PROLINK_PLAYTVPVR: case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO: ir_codes = ir_codes_pixelview; ir->gpio_addr = MO_GP1_IO; @@ -524,6 +194,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci) ir->mask_keyup = 0x80; ir->polling = 1; /* ms */ break; + case CX88_BOARD_KWORLD_LTV883: + ir_codes = ir_codes_pixelview; + ir->gpio_addr = MO_GP1_IO; + ir->mask_keycode = 0x1f; + ir->mask_keyup = 0x60; + ir->polling = 1; /* ms */ + break; case CX88_BOARD_ADSTECH_DVB_T_PCI: ir_codes = ir_codes_adstech_dvb_t_pci; ir->gpio_addr = MO_GP1_IO; diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 073494ceab0..6c97aa740d2 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -227,7 +227,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .minimum = 0x00, .maximum = 0xff, .step = 1, - .default_value = 0, + .default_value = 0x7f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 128, @@ -255,7 +255,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .minimum = 0, .maximum = 0xff, .step = 1, - .default_value = 0, + .default_value = 0x7f, .type = V4L2_CTRL_TYPE_INTEGER, }, .off = 128, @@ -300,7 +300,7 @@ static struct cx88_ctrl cx8800_ctls[] = { .minimum = 0, .maximum = 0x3f, .step = 1, - .default_value = 0x1f, + .default_value = 0x3f, .type = V4L2_CTRL_TYPE_INTEGER, }, .reg = AUD_VOL_CTL, @@ -336,17 +336,17 @@ static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bi return 1; /* is it free? */ - down(&core->lock); + mutex_lock(&core->lock); if (dev->resources & bit) { /* no, someone else uses it */ - up(&core->lock); + mutex_unlock(&core->lock); return 0; } /* it's free, grab it */ fh->resources |= bit; dev->resources |= bit; dprintk(1,"res: get %d\n",bit); - up(&core->lock); + mutex_unlock(&core->lock); return 1; } @@ -366,14 +366,13 @@ static void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits) { struct cx88_core *core = dev->core; - if ((fh->resources & bits) != bits) - BUG(); + BUG_ON((fh->resources & bits) != bits); - down(&core->lock); + mutex_lock(&core->lock); fh->resources &= ~bits; dev->resources &= ~bits; dprintk(1,"res: put %d\n",bits); - up(&core->lock); + mutex_unlock(&core->lock); } /* ------------------------------------------------------------------ */ @@ -909,7 +908,8 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl) value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); switch (ctl->id) { case V4L2_CID_AUDIO_BALANCE: - ctl->value = (value & 0x40) ? (value & 0x3f) : (0x40 - (value & 0x3f)); + ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40) + : (0x7f - (value & 0x7f)); break; case V4L2_CID_AUDIO_VOLUME: ctl->value = 0x3f - (value & 0x3f); @@ -918,9 +918,9 @@ static int get_control(struct cx88_core *core, struct v4l2_control *ctl) ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; break; } - printk("get_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", - ctl->id, c->reg, ctl->value, - c->mask, c->sreg ? " [shadowed]" : ""); + dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", + ctl->id, c->v.name, ctl->value, c->reg, + value,c->mask, c->sreg ? " [shadowed]" : ""); return 0; } @@ -946,7 +946,7 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl) mask=c->mask; switch (ctl->id) { case V4L2_CID_AUDIO_BALANCE: - value = (ctl->value < 0x40) ? (0x40 - ctl->value) : ctl->value; + value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40); break; case V4L2_CID_AUDIO_VOLUME: value = 0x3f - (ctl->value & 0x3f); @@ -969,9 +969,9 @@ static int set_control(struct cx88_core *core, struct v4l2_control *ctl) value = ((ctl->value - c->off) << c->shift) & c->mask; break; } - printk("set_control id=0x%X reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", - ctl->id, c->reg, value, - mask, c->sreg ? " [shadowed]" : ""); + dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", + ctl->id, c->v.name, ctl->value, c->reg, value, + mask, c->sreg ? " [shadowed]" : ""); if (c->sreg) { cx_sandor(c->sreg, c->reg, mask, value); } else { @@ -987,8 +987,7 @@ static void init_controls(struct cx88_core *core) for (i = 0; i < CX8800_CTLS; i++) { ctrl.id=cx8800_ctls[i].v.id; - ctrl.value=cx8800_ctls[i].v.default_value - +cx8800_ctls[i].off; + ctrl.value=cx8800_ctls[i].v.default_value; set_control(core, &ctrl); } } @@ -1252,7 +1251,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, { int err; - dprintk( 1, "CORE IOCTL: 0x%x\n", cmd ); + dprintk(2, "CORE IOCTL: 0x%x\n", cmd ); if (video_debug > 1) v4l_print_ioctl(core->name,cmd); @@ -1291,9 +1290,9 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, if (i == ARRAY_SIZE(tvnorms)) return -EINVAL; - down(&core->lock); + mutex_lock(&core->lock); cx88_set_tvnorm(core,&tvnorms[i]); - up(&core->lock); + mutex_unlock(&core->lock); return 0; } @@ -1343,10 +1342,10 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, if (*i >= 4) return -EINVAL; - down(&core->lock); + mutex_lock(&core->lock); cx88_newstation(core); video_mux(core,*i); - up(&core->lock); + mutex_unlock(&core->lock); return 0; } @@ -1438,7 +1437,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, return -EINVAL; if (1 == radio && f->type != V4L2_TUNER_RADIO) return -EINVAL; - down(&core->lock); + mutex_lock(&core->lock); core->freq = f->frequency; cx88_newstation(core); cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f); @@ -1447,7 +1446,7 @@ int cx88_do_ioctl(struct inode *inode, struct file *file, int radio, msleep (10); cx88_set_tvaudio(core); - up(&core->lock); + mutex_unlock(&core->lock); return 0; } @@ -1921,11 +1920,11 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, pci_set_drvdata(pci_dev,dev); /* initial device configuration */ - down(&core->lock); + mutex_lock(&core->lock); cx88_set_tvnorm(core,tvnorms); init_controls(core); video_mux(core,0); - up(&core->lock); + mutex_unlock(&core->lock); /* start tvaudio thread */ if (core->tuner_type != TUNER_ABSENT) diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index e9fd55b57fa..cfa8668784b 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -35,6 +35,7 @@ #include "cx88-reg.h" #include <linux/version.h> +#include <linux/mutex.h> #define CX88_VERSION_CODE KERNEL_VERSION(0,0,5) #ifndef TRUE @@ -62,7 +63,7 @@ /* need "shadow" registers for some write-only ones ... */ #define SHADOW_AUD_VOL_CTL 1 #define SHADOW_AUD_BAL_CTL 2 -#define SHADOW_MAX 2 +#define SHADOW_MAX 3 /* FM Radio deemphasis type */ enum cx88_deemph_type { @@ -187,6 +188,8 @@ extern struct sram_channel cx88_sram_channels[]; #define CX88_BOARD_DNTV_LIVE_DVB_T_PRO 42 #define CX88_BOARD_KWORLD_DVB_T_CX22702 43 #define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL 44 +#define CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT 45 +#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID 46 enum cx88_itype { CX88_VMUX_COMPOSITE1 = 1, @@ -308,8 +311,7 @@ struct cx88_core { /* IR remote control state */ struct cx88_IR *ir; - struct semaphore lock; - + struct mutex lock; /* various v4l controls */ u32 freq; diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c index 2831bdd1205..0fcc935828f 100644 --- a/drivers/media/video/dpc7146.c +++ b/drivers/media/video/dpc7146.c @@ -1,6 +1,6 @@ /* dpc7146.c - v4l2 driver for the dpc7146 demonstration board - + Copyright (C) 2000-2003 Michael Hunold <michael@mihu.de> This program is free software; you can redistribute it and/or modify @@ -52,7 +52,7 @@ #define SAA711X_DECODED_BYTES_OF_TS_2 0x1C #define SAA711X_STATUS_BYTE 0x1F -#define DPC_BOARD_CAN_DO_VBI(dev) (dev->revision != 0) +#define DPC_BOARD_CAN_DO_VBI(dev) (dev->revision != 0) static int debug = 0; module_param(debug, int, 0); @@ -81,16 +81,16 @@ struct dpc struct video_device *video_dev; struct video_device *vbi_dev; - struct i2c_adapter i2c_adapter; + struct i2c_adapter i2c_adapter; struct i2c_client *saa7111a; - + int cur_input; /* current input */ }; /* fixme: add vbi stuff here */ static int dpc_probe(struct saa7146_dev* dev) { - struct dpc* dpc = NULL; + struct dpc* dpc = NULL; struct i2c_client *client; struct list_head *item; @@ -118,20 +118,20 @@ static int dpc_probe(struct saa7146_dev* dev) /* loop through all i2c-devices on the bus and look who is there */ list_for_each(item,&dpc->i2c_adapter.clients) { client = list_entry(item, struct i2c_client, list); - if( I2C_SAA7111A == client->addr ) + if( I2C_SAA7111A == client->addr ) dpc->saa7111a = client; } /* check if all devices are present */ if( 0 == dpc->saa7111a ) { - DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n")); + DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n")); i2c_del_adapter(&dpc->i2c_adapter); kfree(dpc); return -ENODEV; } - - /* all devices are present, probe was successful */ - DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n")); + + /* all devices are present, probe was successful */ + DEB_D(("dpc_v4l2.o: dpc_probe succeeded for this device.\n")); /* we store the pointer in our private data field */ dev->ext_priv = dpc; @@ -182,7 +182,7 @@ static struct saa7146_ext_vv vv_data; static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) { struct dpc* dpc = (struct dpc*)dev->ext_priv; - + DEB_D(("dpc_v4l2.o: dpc_attach called.\n")); /* checking for i2c-devices can be omitted here, because we @@ -193,7 +193,7 @@ static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data ERR(("cannot register capture v4l2 device. skipping.\n")); return -1; } - + /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) { if( 0 != saa7146_register_device(&dpc->vbi_dev, dev, "dpc", VFL_TYPE_VBI)) { @@ -205,18 +205,18 @@ static int dpc_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data printk("dpc: found 'dpc7146 demonstration board'-%d.\n",dpc_num); dpc_num++; - + /* the rest */ dpc->cur_input = 0; dpc_init_done(dev); - + return 0; } static int dpc_detach(struct saa7146_dev* dev) { struct dpc* dpc = (struct dpc*)dev->ext_priv; - + DEB_EE(("dev:%p\n",dev)); i2c_release_client(dpc->saa7111a); @@ -238,25 +238,25 @@ static int dpc_detach(struct saa7146_dev* dev) int dpc_vbi_bypass(struct saa7146_dev* dev) { struct dpc* dpc = (struct dpc*)dev->ext_priv; - + int i = 1; /* switch bypass in saa7111a */ if ( 0 != dpc->saa7111a->driver->command(dpc->saa7111a,SAA711X_VBI_BYPASS, &i)) { printk("dpc_v4l2.o: VBI_BYPASS: could not address saa7111a.\n"); return -1; - } + } return 0; } #endif -static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) { struct saa7146_dev *dev = fh->dev; struct dpc* dpc = (struct dpc*)dev->ext_priv; /* - struct saa7146_vv *vv = dev->vv_data; + struct saa7146_vv *vv = dev->vv_data; */ switch(cmd) { @@ -264,11 +264,11 @@ static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) { struct v4l2_input *i = arg; DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index)); - + if( i->index < 0 || i->index >= DPC_INPUTS) { return -EINVAL; } - + memcpy(i, &dpc_inputs[i->index], sizeof(struct v4l2_input)); DEB_D(("dpc_v4l2.o: v4l2_ioctl: VIDIOC_ENUMINPUT %d.\n",i->index)); @@ -289,13 +289,13 @@ static int dpc_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) if (input < 0 || input >= DPC_INPUTS) { return -EINVAL; } - + dpc->cur_input = input; /* fixme: switch input here, switch audio, too! */ // saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync); printk("dpc_v4l2.o: VIDIOC_S_INPUT: fixme switch input.\n"); - + return 0; } default: @@ -334,8 +334,8 @@ static struct saa7146_standard standard[] = { static struct saa7146_extension extension; static struct saa7146_pci_extension_data dpc = { - .ext_priv = "Multimedia eXtension Board", - .ext = &extension, + .ext_priv = "Multimedia eXtension Board", + .ext = &extension, }; static struct pci_device_id pci_tbl[] = { @@ -357,7 +357,7 @@ static struct saa7146_ext_vv vv_data = { .capabilities = V4L2_CAP_VBI_CAPTURE, .stds = &standard[0], .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), - .std_callback = &std_callback, + .std_callback = &std_callback, .ioctls = &ioctls[0], .ioctl = dpc_ioctl, }; @@ -365,7 +365,7 @@ static struct saa7146_ext_vv vv_data = { static struct saa7146_extension extension = { .name = "dpc7146 demonstration board", .flags = SAA7146_USE_I2C_IRQ, - + .pci_tbl = &pci_tbl[0], .module = THIS_MODULE, @@ -375,7 +375,7 @@ static struct saa7146_extension extension = { .irq_mask = 0, .irq_func = NULL, -}; +}; static int __init dpc_init_module(void) { @@ -383,7 +383,7 @@ static int __init dpc_init_module(void) DEB_S(("failed to register extension.\n")); return -ENODEV; } - + return 0; } diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig index 885fd017008..5a793ae7cc2 100644 --- a/drivers/media/video/em28xx/Kconfig +++ b/drivers/media/video/em28xx/Kconfig @@ -5,6 +5,7 @@ config VIDEO_EM28XX select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_IR + select VIDEO_SAA711X ---help--- This is a video4linux driver for Empia 28xx based TV cards. diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 58f7b4194a0..4e22fc4889e 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -72,6 +72,24 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, }}, }, + [EM2820_BOARD_KWORLD_PVRTV2800RF] = { + .name = "Kworld PVR TV 2800 RF", + .is_em2800 = 0, + .vchannels = 2, + .norm = VIDEO_MODE_PAL, + .tda9887_conf = TDA9887_PRESENT, + .has_tuner = 1, + .decoder = EM28XX_SAA7113, + .input = {{ + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = 1, + },{ + .type = EM28XX_VMUX_SVIDEO, + .vmux = 9, + .amux = 1, + }}, + }, [EM2820_BOARD_TERRATEC_CINERGY_250] = { .name = "Terratec Cinergy 250 USB", .vchannels = 3, @@ -83,7 +101,7 @@ struct em28xx_board em28xx_boards[] = { .input = {{ .type = EM28XX_VMUX_TELEVISION, .vmux = 2, - .amux = 0, + .amux = 1, },{ .type = EM28XX_VMUX_COMPOSITE1, .vmux = 0, @@ -257,27 +275,51 @@ struct usb_device_id em28xx_id_table [] = { { }, }; +void em28xx_pre_card_setup(struct em28xx *dev) +{ + /* request some modules */ + switch(dev->model){ + case EM2880_BOARD_TERRATEC_PRODIGY_XS: + case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: + case EM2880_BOARD_TERRATEC_HYBRID_XS: + { + em28xx_write_regs_req(dev, 0x00, 0x08, "\x7d", 1); // reset through GPIO? + break; + } + } +} + void em28xx_card_setup(struct em28xx *dev) { /* request some modules */ - if (dev->model == EM2820_BOARD_HAUPPAUGE_WINTV_USB_2) { - struct tveeprom tv; + switch(dev->model){ + case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: + { + struct tveeprom tv; #ifdef CONFIG_MODULES - request_module("tveeprom"); - request_module("ir-kbd-i2c"); - request_module("msp3400"); + request_module("tveeprom"); + request_module("ir-kbd-i2c"); + request_module("msp3400"); #endif - /* Call first TVeeprom */ + /* Call first TVeeprom */ + + dev->i2c_client.addr = 0xa0 >> 1; + tveeprom_hauppauge_analog(&dev->i2c_client, &tv, dev->eedata); - 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 == AUDIO_CHIP_MSP34XX) { + dev->i2s_speed=2048000; + dev->has_msp34xx=1; + } else + dev->has_msp34xx=0; + break; + } + case EM2820_BOARD_KWORLD_PVRTV2800RF: + { + em28xx_write_regs_req(dev,0x00,0x08, "\xf9", 1); // GPIO enables sound on KWORLD PVR TV 2800RF + break; + } - dev->tuner_type= tv.tuner_type; - if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { - dev->i2s_speed=2048000; - dev->has_msp34xx=1; - } else - dev->has_msp34xx=0; } } diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c index 6ca8631bc36..5b6cece37ae 100644 --- a/drivers/media/video/em28xx/em28xx-i2c.c +++ b/drivers/media/video/em28xx/em28xx-i2c.c @@ -420,7 +420,6 @@ static int em28xx_set_tuner(int check_eeprom, struct i2c_client *client) tun_setup.mode_mask = T_ANALOG_TV | T_RADIO; tun_setup.type = dev->tuner_type; tun_setup.addr = dev->tuner_addr; - em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup); } diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 30dfa5370c7..31e89e4f18b 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -43,91 +43,6 @@ 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) -/* ---------------------------------------------------------------------- */ - -static IR_KEYTAB_TYPE ir_codes_em_terratec[IR_KEYTAB_SIZE] = { - [ 0x01 ] = KEY_CHANNEL, - [ 0x02 ] = KEY_SELECT, - [ 0x03 ] = KEY_MUTE, - [ 0x04 ] = KEY_POWER, - [ 0x05 ] = KEY_KP1, - [ 0x06 ] = KEY_KP2, - [ 0x07 ] = KEY_KP3, - [ 0x08 ] = KEY_CHANNELUP, - [ 0x09 ] = KEY_KP4, - [ 0x0a ] = KEY_KP5, - [ 0x0b ] = KEY_KP6, - [ 0x0c ] = KEY_CHANNELDOWN, - [ 0x0d ] = KEY_KP7, - [ 0x0e ] = KEY_KP8, - [ 0x0f ] = KEY_KP9, - [ 0x10 ] = KEY_VOLUMEUP, - [ 0x11 ] = KEY_KP0, - [ 0x12 ] = KEY_MENU, - [ 0x13 ] = KEY_PRINT, - [ 0x14 ] = KEY_VOLUMEDOWN, - [ 0x16 ] = KEY_PAUSE, - [ 0x18 ] = KEY_RECORD, - [ 0x19 ] = KEY_REWIND, - [ 0x1a ] = KEY_PLAY, - [ 0x1b ] = KEY_FORWARD, - [ 0x1c ] = KEY_BACKSPACE, - [ 0x1e ] = KEY_STOP, - [ 0x40 ] = KEY_ZOOM, -}; - -static IR_KEYTAB_TYPE ir_codes_em_pinnacle_usb[IR_KEYTAB_SIZE] = { - [ 0x3a ] = KEY_KP0, - [ 0x31 ] = KEY_KP1, - [ 0x32 ] = KEY_KP2, - [ 0x33 ] = KEY_KP3, - [ 0x34 ] = KEY_KP4, - [ 0x35 ] = KEY_KP5, - [ 0x36 ] = KEY_KP6, - [ 0x37 ] = KEY_KP7, - [ 0x38 ] = KEY_KP8, - [ 0x39 ] = KEY_KP9, - - [ 0x2f ] = KEY_POWER, - - [ 0x2e ] = KEY_P, - [ 0x1f ] = KEY_L, - [ 0x2b ] = KEY_I, - - [ 0x2d ] = KEY_ZOOM, - [ 0x1e ] = KEY_ZOOM, - [ 0x1b ] = KEY_VOLUMEUP, - [ 0x0f ] = KEY_VOLUMEDOWN, - [ 0x17 ] = KEY_CHANNELUP, - [ 0x1c ] = KEY_CHANNELDOWN, - [ 0x25 ] = KEY_INFO, - - [ 0x3c ] = KEY_MUTE, - - [ 0x3d ] = KEY_LEFT, - [ 0x3b ] = KEY_RIGHT, - - [ 0x3f ] = KEY_UP, - [ 0x3e ] = KEY_DOWN, - [ 0x1a ] = KEY_PAUSE, - - [ 0x1d ] = KEY_MENU, - [ 0x19 ] = KEY_PLAY, - [ 0x16 ] = KEY_REWIND, - [ 0x13 ] = KEY_FORWARD, - [ 0x15 ] = KEY_PAUSE, - [ 0x0e ] = KEY_REWIND, - [ 0x0d ] = KEY_PLAY, - [ 0x0b ] = KEY_STOP, - [ 0x07 ] = KEY_FORWARD, - [ 0x27 ] = KEY_RECORD, - [ 0x26 ] = KEY_TUNER, - [ 0x29 ] = KEY_TEXT, - [ 0x2a ] = KEY_MEDIA, - [ 0x18 ] = KEY_EPG, - [ 0x27 ] = KEY_RECORD, -}; - /* ----------------------------------------------------------------------- */ static int get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw) diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c index 94a14a2bb6d..780342f7b23 100644 --- a/drivers/media/video/em28xx/em28xx-video.c +++ b/drivers/media/video/em28xx/em28xx-video.c @@ -28,6 +28,7 @@ #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> @@ -59,8 +60,14 @@ 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 }; module_param_array(card, int, NULL, 0444); +module_param_array(video_nr, int, NULL, 0444); +module_param_array(vbi_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"); static int tuner = -1; module_param(tuner, int, 0444); @@ -70,6 +77,9 @@ static unsigned int video_debug = 0; 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 tv norms */ static struct em28xx_tvnorm tvnorms[] = { { @@ -91,23 +101,6 @@ static struct em28xx_tvnorm tvnorms[] = { } }; -static const unsigned char saa7114_i2c_init[] = { - 0x00,0x00,0x01,0x08,0x02,0xc4,0x03,0x30,0x04,0x90,0x05,0x90,0x06,0xeb,0x07,0xe0, - 0x08,0x88,0x09,0x40,0x0a,0x80,0x0b,0x44,0x0c,0x40,0x0d,0x00,0x0e,0x81,0x0f,0x2a, - 0x10,0x06,0x11,0x00,0x12,0xc8,0x13,0x80,0x14,0x00,0x15,0x11,0x16,0x01,0x17,0x42, - 0x18,0x40,0x19,0x80,0x40,0x00,0x41,0xff,0x42,0xff,0x43,0xff,0x44,0xff,0x45,0xff, - 0x46,0xff,0x47,0xff,0x48,0xff,0x49,0xff,0x4a,0xff,0x4b,0xff,0x4c,0xff,0x4d,0xff, - 0x4e,0xff,0x4f,0xff,0x50,0xff,0x51,0xff,0x52,0xff,0x53,0xff,0x54,0x5f,0x55,0xff, - 0x56,0xff,0x57,0xff,0x58,0x00,0x59,0x47,0x5a,0x03,0x5b,0x03,0x5d,0x3e,0x5e,0x00, - 0x80,0x1c,0x83,0x01,0x84,0xa5,0x85,0x10,0x86,0x45,0x87,0x41,0x88,0xf0,0x88,0x00, - 0x88,0xf0,0x90,0x00,0x91,0x08,0x92,0x00,0x93,0x80,0x94,0x08,0x95,0x00,0x96,0xc0, - 0x97,0x02,0x98,0x13,0x99,0x00,0x9a,0x38,0x9b,0x01,0x9c,0x80,0x9d,0x02,0x9e,0x06, - 0x9f,0x01,0xa0,0x01,0xa1,0x00,0xa2,0x00,0xa4,0x80,0xa5,0x36,0xa6,0x36,0xa8,0x67, - 0xa9,0x04,0xaa,0x00,0xac,0x33,0xad,0x02,0xae,0x00,0xb0,0xcd,0xb1,0x04,0xb2,0xcd, - 0xb3,0x04,0xb4,0x01,0xb8,0x00,0xb9,0x00,0xba,0x00,0xbb,0x00,0xbc,0x00,0xbd,0x00, - 0xbe,0x00,0xbf,0x00 -}; - #define TVNORMS ARRAY_SIZE(tvnorms) /* supported controls */ @@ -134,65 +127,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = { } }; -/* FIXME: These are specific to saa711x - should be moved to its code */ -static struct v4l2_queryctrl saa711x_qctrl[] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = -128, - .maximum = 127, - .step = 1, - .default_value = 0, - .flags = 0, - },{ - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0x0, - .maximum = 0x1f, - .step = 0x1, - .default_value = 0x10, - .flags = 0, - },{ - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0x0, - .maximum = 0x1f, - .step = 0x1, - .default_value = 0x10, - .flags = 0, - },{ - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red chroma balance", - .minimum = -128, - .maximum = 127, - .step = 1, - .default_value = 0, - .flags = 0, - },{ - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue chroma balance", - .minimum = -128, - .maximum = 127, - .step = 1, - .default_value = 0, - .flags = 0, - },{ - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0x0, - .maximum = 0x3f, - .step = 0x1, - .default_value = 0x20, - .flags = 0, - } -}; - static struct usb_driver em28xx_usb_driver; static DEFINE_MUTEX(em28xx_sysfs_lock); @@ -211,6 +145,11 @@ static int em28xx_config(struct em28xx *dev) 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); + em28xx_audio_usb_mute(dev, 1); dev->mute = 1; /* maybe not the right place... */ dev->volume = 0x1f; @@ -230,22 +169,9 @@ static int em28xx_config(struct em28xx *dev) static void em28xx_config_i2c(struct em28xx *dev) { struct v4l2_frequency f; - struct video_decoder_init em28xx_vdi = {.data = NULL }; - - - /* configure decoder */ - if(dev->model == EM2820_BOARD_MSI_VOX_USB_2){ - em28xx_vdi.data=saa7114_i2c_init; - em28xx_vdi.len=sizeof(saa7114_i2c_init); - } - - - em28xx_i2c_call_clients(dev, DECODER_INIT, &em28xx_vdi); - em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &dev->ctl_input); -/* em28xx_i2c_call_clients(dev,DECODER_SET_PICTURE, &dev->vpic); */ -/* em28xx_i2c_call_clients(dev,DECODER_SET_NORM,&dev->tvnorm->id); */ -/* em28xx_i2c_call_clients(dev,DECODER_ENABLE_OUTPUT,&output); */ -/* em28xx_i2c_call_clients(dev,DECODER_DUMP, NULL); */ + em28xx_i2c_call_clients(dev, VIDIOC_INT_RESET, NULL); + em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &dev->ctl_input); + em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL); /* configure tuner */ f.tuner = 0; @@ -285,8 +211,7 @@ static void video_mux(struct em28xx *dev, int index) dev->ctl_input = index; dev->ctl_ainput = INPUT(index)->amux; - em28xx_i2c_call_clients(dev, DECODER_SET_INPUT, &input); - + em28xx_i2c_call_clients(dev, VIDIOC_S_INPUT, &input); em28xx_videodbg("Setting input index=%d, vmux=%d, amux=%d\n",index,input,dev->ctl_ainput); @@ -298,11 +223,11 @@ static void video_mux(struct em28xx *dev, int index) em28xx_audio_source(dev, ainput); } else { switch (dev->ctl_ainput) { - case 0: - ainput = EM28XX_AUDIO_SRC_TUNER; - break; - default: - ainput = EM28XX_AUDIO_SRC_LINE; + case 0: + ainput = EM28XX_AUDIO_SRC_TUNER; + break; + default: + ainput = EM28XX_AUDIO_SRC_LINE; } em28xx_audio_source(dev, ainput); } @@ -323,13 +248,20 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) h = list_entry(list, struct em28xx, devlist); if (h->vdev->minor == minor) { dev = h; + dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + } + if (h->vbi_dev->minor == minor) { + dev = h; + dev->type = V4L2_BUF_TYPE_VBI_CAPTURE; } } + if (NULL == dev) + return -ENODEV; filp->private_data=dev; - - em28xx_videodbg("users=%d\n", dev->users); + em28xx_videodbg("open minor=%d type=%s users=%d\n", + minor,v4l2_type_names[dev->type],dev->users); if (!down_read_trylock(&em28xx_disconnect)) return -ERESTARTSYS; @@ -340,37 +272,36 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) return -EBUSY; } -/* if(dev->vbi_dev->minor == minor){ - dev->type=V4L2_BUF_TYPE_VBI_CAPTURE; - }*/ - if (dev->vdev->minor == minor) { - dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - } - - init_MUTEX(&dev->fileop_lock); /* to 1 == available */ + mutex_init(&dev->fileop_lock); /* to 1 == available */ spin_lock_init(&dev->queue_lock); init_waitqueue_head(&dev->wait_frame); init_waitqueue_head(&dev->wait_stream); - down(&dev->lock); + mutex_lock(&dev->lock); - em28xx_set_alternate(dev); + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + em28xx_set_alternate(dev); - dev->width = norm_maxw(dev); - dev->height = norm_maxh(dev); - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ - dev->bytesperline = dev->width * 2; - dev->hscale = 0; - dev->vscale = 0; + dev->width = norm_maxw(dev); + dev->height = norm_maxh(dev); + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ + dev->bytesperline = dev->width * 2; + dev->hscale = 0; + dev->vscale = 0; - em28xx_capture_start(dev, 1); - em28xx_resolution_set(dev); + em28xx_capture_start(dev, 1); + em28xx_resolution_set(dev); + + /* device needs to be initialized before isoc transfer */ + video_mux(dev, 0); - /* start the transfer */ - errCode = em28xx_init_isoc(dev); - if (errCode) - goto err; + /* start the transfer */ + errCode = em28xx_init_isoc(dev); + if (errCode) + goto err; + + } dev->users++; filp->private_data = dev; @@ -383,10 +314,8 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) dev->state |= DEV_INITIALIZED; - video_mux(dev, 0); - - err: - up(&dev->lock); +err: + mutex_unlock(&dev->lock); up_read(&em28xx_disconnect); return errCode; } @@ -400,14 +329,21 @@ static void em28xx_release_resources(struct em28xx *dev) { mutex_lock(&em28xx_sysfs_lock); - em28xx_info("V4L2 device /dev/video%d deregistered\n", - dev->vdev->minor); + /*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); video_unregister_device(dev->vdev); -/* video_unregister_device(dev->vbi_dev); */ + video_unregister_device(dev->vbi_dev); em28xx_i2c_unregister(dev); usb_put_dev(dev->udev); mutex_unlock(&em28xx_sysfs_lock); + + + /* Mark device as unused */ + em28xx_devused&=~(1<<dev->devno); } /* @@ -421,7 +357,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) em28xx_videodbg("users=%d\n", dev->users); - down(&dev->lock); + mutex_lock(&dev->lock); em28xx_uninit_isoc(dev); @@ -430,7 +366,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) /* the device is already disconnect, free the remaining resources */ if (dev->state & DEV_DISCONNECTED) { em28xx_release_resources(dev); - up(&dev->lock); + mutex_unlock(&dev->lock); kfree(dev); return 0; } @@ -446,7 +382,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp) dev->users--; wake_up_interruptible_nr(&dev->open, 1); - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; } @@ -463,32 +399,54 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, int ret = 0; struct em28xx *dev = filp->private_data; - if (down_interruptible(&dev->fileop_lock)) + if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + em28xx_videodbg("V4l2_Buf_type_videocapture is set\n"); + } + if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) { + em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n"); + em28xx_videodbg("not supported yet! ...\n"); + if (copy_to_user(buf, "", 1)) { + mutex_unlock(&dev->fileop_lock); + return -EFAULT; + } + return (1); + } + if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { + em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n"); + em28xx_videodbg("not supported yet! ...\n"); + if (copy_to_user(buf, "", 1)) { + mutex_unlock(&dev->fileop_lock); + return -EFAULT; + } + return (1); + } + + if (mutex_lock_interruptible(&dev->fileop_lock)) return -ERESTARTSYS; if (dev->state & DEV_DISCONNECTED) { em28xx_videodbg("device not present\n"); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { em28xx_videodbg("device misconfigured; close and open it again\n"); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -EIO; } if (dev->io == IO_MMAP) { em28xx_videodbg ("IO method is set to mmap; close and open" " the device again to choose the read method\n"); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -EINVAL; } if (dev->io == IO_NONE) { if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) { em28xx_errdev("read failed, not enough memory\n"); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -ENOMEM; } dev->io = IO_READ; @@ -497,13 +455,13 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, } if (!count) { - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return 0; } if (list_empty(&dev->outqueue)) { if (filp->f_flags & O_NONBLOCK) { - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -EAGAIN; } ret = wait_event_interruptible @@ -511,11 +469,11 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, (!list_empty(&dev->outqueue)) || (dev->state & DEV_DISCONNECTED)); if (ret) { - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return ret; } if (dev->state & DEV_DISCONNECTED) { - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -ENODEV; } } @@ -534,12 +492,12 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count, count = f->buf.length; if (copy_to_user(buf, f->bufmem, count)) { - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -EFAULT; } *f_pos += count; - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return count; } @@ -553,7 +511,7 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) unsigned int mask = 0; struct em28xx *dev = filp->private_data; - if (down_interruptible(&dev->fileop_lock)) + if (mutex_lock_interruptible(&dev->fileop_lock)) return POLLERR; if (dev->state & DEV_DISCONNECTED) { @@ -579,13 +537,13 @@ static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait) if (!list_empty(&dev->outqueue)) mask |= POLLIN | POLLRDNORM; - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return mask; } } - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return POLLERR; } @@ -625,25 +583,25 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) struct em28xx *dev = filp->private_data; - if (down_interruptible(&dev->fileop_lock)) + if (mutex_lock_interruptible(&dev->fileop_lock)) return -ERESTARTSYS; if (dev->state & DEV_DISCONNECTED) { em28xx_videodbg("mmap: device not present\n"); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { em28xx_videodbg ("mmap: Device is misconfigured; close and " "open it again\n"); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -EIO; } if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(dev->frame[0].buf.length)) { - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -EINVAL; } @@ -653,7 +611,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) } if (i == dev->num_frames) { em28xx_videodbg("mmap: user supplied mapping address is out of range\n"); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -EINVAL; } @@ -665,7 +623,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) while (size > 0) { /* size is page-aligned */ if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { em28xx_videodbg("mmap: vm_insert_page failed\n"); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -EAGAIN; } start += PAGE_SIZE; @@ -677,7 +635,7 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) vma->vm_private_data = &dev->frame[i]; em28xx_vm_open(vma); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return 0; } @@ -699,43 +657,6 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) } } -/*FIXME: should be moved to saa711x */ -static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl) -{ - s32 tmp; - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - if ((tmp = em28xx_brightness_get(dev)) < 0) - return -EIO; - ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */ - return 0; - case V4L2_CID_CONTRAST: - if ((ctrl->value = em28xx_contrast_get(dev)) < 0) - return -EIO; - return 0; - case V4L2_CID_SATURATION: - if ((ctrl->value = em28xx_saturation_get(dev)) < 0) - return -EIO; - return 0; - case V4L2_CID_RED_BALANCE: - if ((tmp = em28xx_v_balance_get(dev)) < 0) - return -EIO; - ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */ - return 0; - case V4L2_CID_BLUE_BALANCE: - if ((tmp = em28xx_u_balance_get(dev)) < 0) - return -EIO; - ctrl->value = (s32) ((s8) tmp); /* FIXME: clenaer way to extend sign? */ - return 0; - case V4L2_CID_GAMMA: - if ((ctrl->value = em28xx_gamma_get(dev)) < 0) - return -EIO; - return 0; - default: - return -EINVAL; - } -} - /* * em28xx_set_ctrl() * mute or set new saturation, brightness or contrast @@ -758,27 +679,6 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) } } -/*FIXME: should be moved to saa711x */ -static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl) -{ - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - return em28xx_brightness_set(dev, ctrl->value); - case V4L2_CID_CONTRAST: - return em28xx_contrast_set(dev, ctrl->value); - case V4L2_CID_SATURATION: - return em28xx_saturation_set(dev, ctrl->value); - case V4L2_CID_RED_BALANCE: - return em28xx_v_balance_set(dev, ctrl->value); - case V4L2_CID_BLUE_BALANCE: - return em28xx_u_balance_set(dev, ctrl->value); - case V4L2_CID_GAMMA: - return em28xx_gamma_set(dev, ctrl->value); - default: - return -EINVAL; - } -} - /* * em28xx_stream_interrupt() * stops streaming @@ -799,7 +699,8 @@ static int em28xx_stream_interrupt(struct em28xx *dev) else if (ret) { dev->state |= DEV_MISCONFIGURED; em28xx_videodbg("device is misconfigured; close and " - "open /dev/video%d again\n", dev->vdev->minor); + "open /dev/video%d again\n", + dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN); return ret; } @@ -850,6 +751,181 @@ static int em28xx_set_norm(struct em28xx *dev, int width, int height) return 0; } +static int em28xx_get_fmt(struct em28xx *dev, struct v4l2_format *format) +{ + em28xx_videodbg("VIDIOC_G_FMT: type=%s\n", + (format->type ==V4L2_BUF_TYPE_VIDEO_CAPTURE) ? + "V4L2_BUF_TYPE_VIDEO_CAPTURE" : + (format->type ==V4L2_BUF_TYPE_VBI_CAPTURE) ? + "V4L2_BUF_TYPE_VBI_CAPTURE" : + (format->type ==V4L2_CAP_SLICED_VBI_CAPTURE) ? + "V4L2_BUF_TYPE_SLICED_VBI_CAPTURE " : + "not supported"); + + switch (format->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + { + format->fmt.pix.width = dev->width; + format->fmt.pix.height = dev->height; + format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + format->fmt.pix.bytesperline = dev->bytesperline; + format->fmt.pix.sizeimage = dev->frame_size; + format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ + + em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width, + dev->height); + break; + } + + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + { + format->fmt.sliced.service_set=0; + + em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format); + + if (format->fmt.sliced.service_set==0) + return -EINVAL; + + break; + } + + default: + return -EINVAL; + } + return (0); +} + +static int em28xx_set_fmt(struct em28xx *dev, unsigned int cmd, struct v4l2_format *format) +{ + u32 i; + int ret = 0; + int width = format->fmt.pix.width; + int height = format->fmt.pix.height; + unsigned int hscale, vscale; + unsigned int maxh, maxw; + + maxw = norm_maxw(dev); + maxh = norm_maxh(dev); + + em28xx_videodbg("%s: type=%s\n", + cmd == VIDIOC_TRY_FMT ? + "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", + format->type == V4L2_BUF_TYPE_VIDEO_CAPTURE ? + "V4L2_BUF_TYPE_VIDEO_CAPTURE" : + format->type == V4L2_BUF_TYPE_VBI_CAPTURE ? + "V4L2_BUF_TYPE_VBI_CAPTURE " : + "not supported"); + + if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) { + em28xx_i2c_call_clients(dev,VIDIOC_G_FMT,format); + + if (format->fmt.sliced.service_set==0) + return -EINVAL; + + return 0; + } + + + if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + em28xx_videodbg("%s: requested %dx%d\n", + cmd == VIDIOC_TRY_FMT ? + "VIDIOC_TRY_FMT" : "VIDIOC_S_FMT", + format->fmt.pix.width, format->fmt.pix.height); + + /* FIXME: Move some code away from here */ + /* 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; + + 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; + } + + if ((hscale = (((unsigned long)maxw) << 12) / width - 4096L) >= 0x4000) + hscale = 0x3fff; + + width = (((unsigned long)maxw) << 12) / (hscale + 4096L); + + if ((vscale = (((unsigned long)maxh) << 12) / height - 4096L) >= 0x4000) + vscale = 0x3fff; + + height = (((unsigned long)maxh) << 12) / (vscale + 4096L); + + format->fmt.pix.width = width; + format->fmt.pix.height = height; + format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; + format->fmt.pix.bytesperline = width * 2; + format->fmt.pix.sizeimage = width * 2 * height; + format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + format->fmt.pix.field = V4L2_FIELD_INTERLACED; + + em28xx_videodbg("%s: returned %dx%d (%d, %d)\n", + cmd == VIDIOC_TRY_FMT ? + "VIDIOC_TRY_FMT" :"VIDIOC_S_FMT", + format->fmt.pix.width, format->fmt.pix.height, hscale, vscale); + + if (cmd == VIDIOC_TRY_FMT) + return 0; + + for (i = 0; i < dev->num_frames; i++) + if (dev->frame[i].vma_use_count) { + em28xx_videodbg("VIDIOC_S_FMT failed. " + "Unmap the buffers first.\n"); + return -EINVAL; + } + + /* stop io in case it is already in progress */ + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n"); + if ((ret = em28xx_stream_interrupt(dev))) + return ret; + } + + em28xx_release_buffers(dev); + dev->io = IO_NONE; + + /* set new image size */ + dev->width = width; + dev->height = height; + dev->frame_size = dev->width * dev->height * 2; + dev->field_size = dev->frame_size >> 1; + dev->bytesperline = dev->width * 2; + dev->hscale = hscale; + dev->vscale = vscale; + em28xx_uninit_isoc(dev); + em28xx_set_alternate(dev); + em28xx_capture_start(dev, 1); + em28xx_resolution_set(dev); + em28xx_init_isoc(dev); + + return 0; +} + /* * em28xx_v4l2_do_ioctl() * This function is _not_ called directly, but from @@ -865,392 +941,325 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp, switch (cmd) { /* ---------- tv norms ---------- */ case VIDIOC_ENUMSTD: - { - struct v4l2_standard *e = arg; - unsigned int i; + { + struct v4l2_standard *e = arg; + unsigned int i; - i = e->index; - if (i >= TVNORMS) - return -EINVAL; - ret = v4l2_video_std_construct(e, tvnorms[e->index].id, - tvnorms[e->index].name); - e->index = i; - if (ret < 0) - return ret; - return 0; - } + i = e->index; + if (i >= TVNORMS) + return -EINVAL; + ret = v4l2_video_std_construct(e, tvnorms[e->index].id, + tvnorms[e->index].name); + e->index = i; + if (ret < 0) + return ret; + return 0; + } case VIDIOC_G_STD: - { - v4l2_std_id *id = arg; + { + v4l2_std_id *id = arg; - *id = dev->tvnorm->id; - return 0; - } + *id = dev->tvnorm->id; + return 0; + } case VIDIOC_S_STD: - { - v4l2_std_id *id = arg; - unsigned int i; + { + v4l2_std_id *id = arg; + unsigned int i; + for (i = 0; i < TVNORMS; i++) + if (*id == tvnorms[i].id) + break; + if (i == TVNORMS) for (i = 0; i < TVNORMS; i++) - if (*id == tvnorms[i].id) + if (*id & tvnorms[i].id) break; - if (i == TVNORMS) - for (i = 0; i < TVNORMS; i++) - if (*id & tvnorms[i].id) - break; - if (i == TVNORMS) - return -EINVAL; - - down(&dev->lock); - dev->tvnorm = &tvnorms[i]; + if (i == TVNORMS) + return -EINVAL; - em28xx_set_norm(dev, dev->width, dev->height); + mutex_lock(&dev->lock); + dev->tvnorm = &tvnorms[i]; -/* - dev->width=norm_maxw(dev); - dev->height=norm_maxh(dev); - dev->frame_size=dev->width*dev->height*2; - dev->field_size=dev->frame_size>>1; - dev->bytesperline=dev->width*2; - dev->hscale=0; - dev->vscale=0; + em28xx_set_norm(dev, dev->width, dev->height); - em28xx_resolution_set(dev); -*/ -/* - em28xx_uninit_isoc(dev); - em28xx_set_alternate(dev); - em28xx_capture_start(dev, 1); - em28xx_resolution_set(dev); - em28xx_init_isoc(dev); -*/ - em28xx_i2c_call_clients(dev, DECODER_SET_NORM, - &tvnorms[i].mode); - em28xx_i2c_call_clients(dev, VIDIOC_S_STD, - &dev->tvnorm->id); + em28xx_i2c_call_clients(dev, VIDIOC_S_STD, + &dev->tvnorm->id); - up(&dev->lock); + mutex_unlock(&dev->lock); - return 0; - } + return 0; + } - /* ------ input switching ---------- */ + /* ------ input switching ---------- */ case VIDIOC_ENUMINPUT: - { - struct v4l2_input *i = arg; - unsigned int n; - 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", - }; - - n = i->index; - if (n >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(n)->type) - return -EINVAL; - memset(i, 0, sizeof(*i)); - 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; - for (n = 0; n < ARRAY_SIZE(tvnorms); n++) - i->std |= tvnorms[n].id; - return 0; - } - + { + struct v4l2_input *i = arg; + unsigned int n; + 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", + }; + + n = i->index; + if (n >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(n)->type) + return -EINVAL; + memset(i, 0, sizeof(*i)); + 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; + for (n = 0; n < ARRAY_SIZE(tvnorms); n++) + i->std |= tvnorms[n].id; + return 0; + } case VIDIOC_G_INPUT: - { - int *i = arg; - *i = dev->ctl_input; - - return 0; - } + { + int *i = arg; + *i = dev->ctl_input; + return 0; + } case VIDIOC_S_INPUT: - { - int *index = arg; - - if (*index >= MAX_EM28XX_INPUT) - return -EINVAL; - if (0 == INPUT(*index)->type) - return -EINVAL; + { + int *index = arg; - down(&dev->lock); - video_mux(dev, *index); - up(&dev->lock); + if (*index >= MAX_EM28XX_INPUT) + return -EINVAL; + if (0 == INPUT(*index)->type) + return -EINVAL; - return 0; - } + mutex_lock(&dev->lock); + video_mux(dev, *index); + mutex_unlock(&dev->lock); + return 0; + } case VIDIOC_G_AUDIO: - { - struct v4l2_audio *a = arg; - unsigned int index = a->index; + { + struct v4l2_audio *a = arg; + unsigned int index = a->index; - if (a->index > 1) - return -EINVAL; - memset(a, 0, sizeof(*a)); - index = dev->ctl_ainput; + if (a->index > 1) + return -EINVAL; + memset(a, 0, sizeof(*a)); + 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; + if (index == 0) { + strcpy(a->name, "Television"); + } else { + strcpy(a->name, "Line In"); } - + a->capability = V4L2_AUDCAP_STEREO; + a->index = index; + return 0; + } case VIDIOC_S_AUDIO: - { - struct v4l2_audio *a = arg; - if (a->index != dev->ctl_ainput) - return -EINVAL; + { + struct v4l2_audio *a = arg; - return 0; - } + if (a->index != dev->ctl_ainput) + return -EINVAL; - /* --- controls ---------------------------------------------- */ + return 0; + } + + /* --- controls ---------------------------------------------- */ case VIDIOC_QUERYCTRL: - { - struct v4l2_queryctrl *qc = arg; - int i, id=qc->id; - - 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; - } - } - } - if (dev->decoder == EM28XX_TVP5150) { - em28xx_i2c_call_clients(dev,cmd,qc); - if (qc->type) - return 0; - else - return -EINVAL; - } - for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) { - if (qc->id && qc->id == saa711x_qctrl[i].id) { - memcpy(qc, &(saa711x_qctrl[i]), - sizeof(*qc)); - return 0; - } - } + { + struct v4l2_queryctrl *qc = arg; + int i, id=qc->id; - return -EINVAL; - } + memset(qc,0,sizeof(*qc)); + qc->id=id; - case VIDIOC_G_CTRL: - { - struct v4l2_control *ctrl = arg; - int retval=-EINVAL; - - if (!dev->has_msp34xx) - retval=em28xx_get_ctrl(dev, ctrl); - if (retval==-EINVAL) { - if (dev->decoder == EM28XX_TVP5150) { - em28xx_i2c_call_clients(dev,cmd,arg); + 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; } - - return saa711x_get_ctrl(dev, ctrl); - } else return retval; + } } + em28xx_i2c_call_clients(dev,cmd,qc); + if (qc->type) + return 0; + else + return -EINVAL; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control *ctrl = arg; + int retval=-EINVAL; + if (!dev->has_msp34xx) + retval=em28xx_get_ctrl(dev, ctrl); + if (retval==-EINVAL) { + em28xx_i2c_call_clients(dev,cmd,arg); + return 0; + } else return retval; + } case VIDIOC_S_CTRL: - { - struct v4l2_control *ctrl = arg; - u8 i; - - if (!dev->has_msp34xx){ - 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) - return -ERANGE; - return em28xx_set_ctrl(dev, ctrl); - } - } - } - - if (dev->decoder == EM28XX_TVP5150) { - em28xx_i2c_call_clients(dev,cmd,arg); - return 0; - } else if (!dev->has_msp34xx) { - 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) - return -ERANGE; - return em28xx_set_ctrl(dev, ctrl); - } - } - for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) { - if (ctrl->id == saa711x_qctrl[i].id) { - if (ctrl->value < - saa711x_qctrl[i].minimum - || ctrl->value > - saa711x_qctrl[i].maximum) - return -ERANGE; - return saa711x_set_ctrl(dev, ctrl); - } + { + struct v4l2_control *ctrl = arg; + u8 i; + + if (!dev->has_msp34xx){ + 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) + return -ERANGE; + return em28xx_set_ctrl(dev, ctrl); } } - - return -EINVAL; } - /* --- tuner ioctls ------------------------------------------ */ + em28xx_i2c_call_clients(dev,cmd,arg); + return 0; + } + /* --- tuner ioctls ------------------------------------------ */ case VIDIOC_G_TUNER: - { - struct v4l2_tuner *t = arg; - int status = 0; + { + struct v4l2_tuner *t = arg; + int status = 0; - if (0 != t->index) - return -EINVAL; + if (0 != t->index) + return -EINVAL; - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Tuner"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */ + memset(t, 0, sizeof(*t)); + strcpy(t->name, "Tuner"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM; + t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */ /* t->signal = 0xffff;*/ /* em28xx_i2c_call_clients(dev,VIDIOC_G_TUNER,t);*/ - /* No way to get signal strength? */ - down(&dev->lock); - em28xx_i2c_call_clients(dev, DECODER_GET_STATUS, - &status); - up(&dev->lock); - t->signal = - (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0; - - em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal, - t->afc); - return 0; - } + /* No way to get signal strength? */ + mutex_lock(&dev->lock); + em28xx_i2c_call_clients(dev, DECODER_GET_STATUS, + &status); + mutex_unlock(&dev->lock); + t->signal = + (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0; + + em28xx_videodbg("VIDIO_G_TUNER: signal=%x, afc=%x\n", t->signal, + t->afc); + return 0; + } case VIDIOC_S_TUNER: - { - struct v4l2_tuner *t = arg; - int status = 0; + { + struct v4l2_tuner *t = arg; + int status = 0; - if (0 != t->index) - return -EINVAL; - memset(t, 0, sizeof(*t)); - strcpy(t->name, "Tuner"); - t->type = V4L2_TUNER_ANALOG_TV; - t->capability = V4L2_TUNER_CAP_NORM; - t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */ + if (0 != t->index) + return -EINVAL; + memset(t, 0, sizeof(*t)); + strcpy(t->name, "Tuner"); + t->type = V4L2_TUNER_ANALOG_TV; + t->capability = V4L2_TUNER_CAP_NORM; + t->rangehigh = 0xffffffffUL; /* FIXME: set correct range */ /* t->signal = 0xffff; */ - /* No way to get signal strength? */ - down(&dev->lock); - em28xx_i2c_call_clients(dev, DECODER_GET_STATUS, - &status); - up(&dev->lock); - t->signal = - (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0; - - em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n", - t->signal, t->afc); - return 0; - } + /* No way to get signal strength? */ + mutex_lock(&dev->lock); + em28xx_i2c_call_clients(dev, DECODER_GET_STATUS, + &status); + mutex_unlock(&dev->lock); + t->signal = + (status & DECODER_STATUS_GOOD) != 0 ? 0xffff : 0; + + em28xx_videodbg("VIDIO_S_TUNER: signal=%x, afc=%x\n", + t->signal, t->afc); + return 0; + } case VIDIOC_G_FREQUENCY: - { - struct v4l2_frequency *f = arg; + { + struct v4l2_frequency *f = arg; - memset(f, 0, sizeof(*f)); - f->type = V4L2_TUNER_ANALOG_TV; - f->frequency = dev->ctl_freq; + memset(f, 0, sizeof(*f)); + f->type = V4L2_TUNER_ANALOG_TV; + f->frequency = dev->ctl_freq; - return 0; - } + return 0; + } case VIDIOC_S_FREQUENCY: - { - struct v4l2_frequency *f = arg; - - if (0 != f->tuner) - return -EINVAL; + { + struct v4l2_frequency *f = arg; - if (V4L2_TUNER_ANALOG_TV != f->type) - return -EINVAL; + if (0 != f->tuner) + return -EINVAL; - down(&dev->lock); - dev->ctl_freq = f->frequency; - em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, f); - up(&dev->lock); - return 0; - } + if (V4L2_TUNER_ANALOG_TV != f->type) + 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; + } case VIDIOC_CROPCAP: - { - struct v4l2_cropcap *cc = arg; + { + struct v4l2_cropcap *cc = arg; - 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; - } + 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; + } case VIDIOC_STREAMON: - { - int *type = arg; + { + int *type = arg; - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) - return -EINVAL; + if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE + || dev->io != IO_MMAP) + return -EINVAL; - if (list_empty(&dev->inqueue)) - return -EINVAL; + if (list_empty(&dev->inqueue)) + return -EINVAL; - dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ + dev->stream = STREAM_ON; /* FIXME: Start video capture here? */ - em28xx_videodbg("VIDIOC_STREAMON: starting stream\n"); + em28xx_videodbg("VIDIOC_STREAMON: starting stream\n"); - return 0; - } + return 0; + } case VIDIOC_STREAMOFF: - { - int *type = arg; - int ret; - - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) - return -EINVAL; + { + int *type = arg; + int ret; - if (dev->stream == STREAM_ON) { - em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) - return ret; - } - em28xx_empty_framequeues(dev); + if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE + || dev->io != IO_MMAP) + return -EINVAL; - return 0; + if (dev->stream == STREAM_ON) { + em28xx_videodbg ("VIDIOC_STREAMOFF: interrupting stream\n"); + if ((ret = em28xx_stream_interrupt(dev))) + return ret; } + em28xx_empty_framequeues(dev); + + return 0; + } default: return v4l_compat_translate_ioctl(inode, filp, cmd, arg, driver_ioctl); @@ -1280,327 +1289,170 @@ static int em28xx_video_do_ioctl(struct inode *inode, struct file *filp, /* --- capabilities ------------------------------------------ */ case VIDIOC_QUERYCAP: { - struct v4l2_capability *cap = arg; - - memset(cap, 0, sizeof(*cap)); - 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_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (dev->has_tuner) - cap->capabilities |= V4L2_CAP_TUNER; - return 0; - } - - /* --- capture ioctls ---------------------------------------- */ + struct v4l2_capability *cap = arg; + + memset(cap, 0, sizeof(*cap)); + 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->has_tuner) + cap->capabilities |= V4L2_CAP_TUNER; + return 0; + } + /* --- capture ioctls ---------------------------------------- */ case VIDIOC_ENUM_FMT: - { - struct v4l2_fmtdesc *fmtd = arg; - - if (fmtd->index != 0) - return -EINVAL; - memset(fmtd, 0, sizeof(*fmtd)); - 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; - } + { + struct v4l2_fmtdesc *fmtd = arg; + if (fmtd->index != 0) + return -EINVAL; + memset(fmtd, 0, sizeof(*fmtd)); + 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; + } case VIDIOC_G_FMT: - { - struct v4l2_format *format = arg; - - em28xx_videodbg("VIDIOC_G_FMT: type=%s\n", - format->type == - V4L2_BUF_TYPE_VIDEO_CAPTURE ? - "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type == - V4L2_BUF_TYPE_VBI_CAPTURE ? - "V4L2_BUF_TYPE_VBI_CAPTURE " : - "not supported"); - - if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - format->fmt.pix.width = dev->width; - format->fmt.pix.height = dev->height; - format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - format->fmt.pix.bytesperline = dev->bytesperline; - format->fmt.pix.sizeimage = dev->frame_size; - format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - format->fmt.pix.field = dev->interlaced ? V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP; /* FIXME: TOP? NONE? BOTTOM? ALTENATE? */ - - em28xx_videodbg("VIDIOC_G_FMT: %dx%d\n", dev->width, - dev->height); - return 0; - } + return em28xx_get_fmt(dev, (struct v4l2_format *) arg); case VIDIOC_TRY_FMT: case VIDIOC_S_FMT: - { - struct v4l2_format *format = arg; - u32 i; - int ret = 0; - int width = format->fmt.pix.width; - int height = format->fmt.pix.height; - unsigned int hscale, vscale; - unsigned int maxh, maxw; - - maxw = norm_maxw(dev); - maxh = norm_maxh(dev); - -/* int both_fields; */ - - em28xx_videodbg("%s: type=%s\n", - cmd == - VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" : - "VIDIOC_S_FMT", - format->type == - V4L2_BUF_TYPE_VIDEO_CAPTURE ? - "V4L2_BUF_TYPE_VIDEO_CAPTURE" : format->type == - V4L2_BUF_TYPE_VBI_CAPTURE ? - "V4L2_BUF_TYPE_VBI_CAPTURE " : - "not supported"); - - if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - em28xx_videodbg("%s: requested %dx%d\n", - cmd == - VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" : - "VIDIOC_S_FMT", format->fmt.pix.width, - format->fmt.pix.height); - - /* FIXME: Move some code away from here */ - /* 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; - - 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; - } - - if ((hscale = - (((unsigned long)maxw) << 12) / width - 4096L) >= - 0x4000) - hscale = 0x3fff; - width = - (((unsigned long)maxw) << 12) / (hscale + 4096L); - - if ((vscale = - (((unsigned long)maxh) << 12) / height - 4096L) >= - 0x4000) - vscale = 0x3fff; - height = - (((unsigned long)maxh) << 12) / (vscale + 4096L); - - format->fmt.pix.width = width; - format->fmt.pix.height = height; - format->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - format->fmt.pix.bytesperline = width * 2; - format->fmt.pix.sizeimage = width * 2 * height; - format->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - format->fmt.pix.field = V4L2_FIELD_INTERLACED; - - em28xx_videodbg("%s: returned %dx%d (%d, %d)\n", - cmd == - VIDIOC_TRY_FMT ? "VIDIOC_TRY_FMT" : - "VIDIOC_S_FMT", format->fmt.pix.width, - format->fmt.pix.height, hscale, vscale); - - if (cmd == VIDIOC_TRY_FMT) - return 0; - - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].vma_use_count) { - em28xx_videodbg("VIDIOC_S_FMT failed. " - "Unmap the buffers first.\n"); - return -EINVAL; - } + return em28xx_set_fmt(dev, cmd, (struct v4l2_format *)arg); - /* stop io in case it is already in progress */ - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_SET_FMT: interupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) - return ret; - } + case VIDIOC_REQBUFS: + { + struct v4l2_requestbuffers *rb = arg; + u32 i; + int ret; - em28xx_release_buffers(dev); - dev->io = IO_NONE; - - /* set new image size */ - dev->width = width; - dev->height = height; - dev->frame_size = dev->width * dev->height * 2; - dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */ - dev->bytesperline = dev->width * 2; - dev->hscale = hscale; - dev->vscale = vscale; -/* dev->both_fileds = both_fileds; */ - em28xx_uninit_isoc(dev); - em28xx_set_alternate(dev); - em28xx_capture_start(dev, 1); - em28xx_resolution_set(dev); - em28xx_init_isoc(dev); + if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + rb->memory != V4L2_MEMORY_MMAP) + return -EINVAL; - return 0; + if (dev->io == IO_READ) { + em28xx_videodbg ("method is set to read;" + " close and open the device again to" + " choose the mmap I/O method\n"); + return -EINVAL; } - /* --- streaming capture ------------------------------------- */ - case VIDIOC_REQBUFS: - { - struct v4l2_requestbuffers *rb = arg; - u32 i; - int ret; - - if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - rb->memory != V4L2_MEMORY_MMAP) - return -EINVAL; - - if (dev->io == IO_READ) { - em28xx_videodbg ("method is set to read;" - " close and open the device again to" - " choose the mmap I/O method\n"); + for (i = 0; i < dev->num_frames; i++) + if (dev->frame[i].vma_use_count) { + em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n"); return -EINVAL; } - for (i = 0; i < dev->num_frames; i++) - if (dev->frame[i].vma_use_count) { - em28xx_videodbg ("VIDIOC_REQBUFS failed; previous buffers are still mapped\n"); - return -EINVAL; - } - - if (dev->stream == STREAM_ON) { - em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); - if ((ret = em28xx_stream_interrupt(dev))) - return ret; - } - - em28xx_empty_framequeues(dev); + if (dev->stream == STREAM_ON) { + em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n"); + if ((ret = em28xx_stream_interrupt(dev))) + return ret; + } - em28xx_release_buffers(dev); - if (rb->count) - rb->count = - em28xx_request_buffers(dev, rb->count); + em28xx_empty_framequeues(dev); - dev->frame_current = NULL; + em28xx_release_buffers(dev); + if (rb->count) + rb->count = + em28xx_request_buffers(dev, rb->count); - em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n", - rb->count); - dev->io = rb->count ? IO_MMAP : IO_NONE; - return 0; - } + dev->frame_current = NULL; + em28xx_videodbg ("VIDIOC_REQBUFS: setting io method to mmap: num bufs %i\n", + rb->count); + dev->io = rb->count ? IO_MMAP : IO_NONE; + return 0; + } case VIDIOC_QUERYBUF: - { - struct v4l2_buffer *b = arg; + { + struct v4l2_buffer *b = arg; - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b->index >= dev->num_frames || dev->io != IO_MMAP) - return -EINVAL; + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b->index >= dev->num_frames || dev->io != IO_MMAP) + return -EINVAL; - memcpy(b, &dev->frame[b->index].buf, sizeof(*b)); + memcpy(b, &dev->frame[b->index].buf, sizeof(*b)); - if (dev->frame[b->index].vma_use_count) { - b->flags |= V4L2_BUF_FLAG_MAPPED; - } - if (dev->frame[b->index].state == F_DONE) - b->flags |= V4L2_BUF_FLAG_DONE; - else if (dev->frame[b->index].state != F_UNUSED) - b->flags |= V4L2_BUF_FLAG_QUEUED; - return 0; + if (dev->frame[b->index].vma_use_count) { + b->flags |= V4L2_BUF_FLAG_MAPPED; } + if (dev->frame[b->index].state == F_DONE) + b->flags |= V4L2_BUF_FLAG_DONE; + else if (dev->frame[b->index].state != F_UNUSED) + b->flags |= V4L2_BUF_FLAG_QUEUED; + return 0; + } case VIDIOC_QBUF: - { - struct v4l2_buffer *b = arg; - unsigned long lock_flags; + { + struct v4l2_buffer *b = arg; + unsigned long lock_flags; - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || - b->index >= dev->num_frames || dev->io != IO_MMAP) { - return -EINVAL; - } + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + b->index >= dev->num_frames || dev->io != IO_MMAP) { + return -EINVAL; + } - if (dev->frame[b->index].state != F_UNUSED) { - return -EAGAIN; - } - dev->frame[b->index].state = F_QUEUED; + if (dev->frame[b->index].state != F_UNUSED) { + return -EAGAIN; + } + dev->frame[b->index].state = F_QUEUED; - /* add frame to fifo */ - spin_lock_irqsave(&dev->queue_lock, lock_flags); - list_add_tail(&dev->frame[b->index].frame, - &dev->inqueue); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + /* add frame to fifo */ + spin_lock_irqsave(&dev->queue_lock, lock_flags); + list_add_tail(&dev->frame[b->index].frame, + &dev->inqueue); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - return 0; - } + return 0; + } case VIDIOC_DQBUF: - { - struct v4l2_buffer *b = arg; - struct em28xx_frame_t *f; - unsigned long lock_flags; - int ret = 0; + { + struct v4l2_buffer *b = arg; + struct em28xx_frame_t *f; + unsigned long lock_flags; + int ret = 0; - if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || dev->io != IO_MMAP) - return -EINVAL; + if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE + || dev->io != IO_MMAP) + return -EINVAL; - if (list_empty(&dev->outqueue)) { - if (dev->stream == STREAM_OFF) - return -EINVAL; - if (filp->f_flags & O_NONBLOCK) - return -EAGAIN; - ret = wait_event_interruptible - (dev->wait_frame, - (!list_empty(&dev->outqueue)) || - (dev->state & DEV_DISCONNECTED)); - if (ret) - return ret; - if (dev->state & DEV_DISCONNECTED) - return -ENODEV; - } + if (list_empty(&dev->outqueue)) { + if (dev->stream == STREAM_OFF) + return -EINVAL; + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + ret = wait_event_interruptible + (dev->wait_frame, + (!list_empty(&dev->outqueue)) || + (dev->state & DEV_DISCONNECTED)); + if (ret) + return ret; + if (dev->state & DEV_DISCONNECTED) + return -ENODEV; + } - spin_lock_irqsave(&dev->queue_lock, lock_flags); - f = list_entry(dev->outqueue.next, - struct em28xx_frame_t, frame); - list_del(dev->outqueue.next); - spin_unlock_irqrestore(&dev->queue_lock, lock_flags); + spin_lock_irqsave(&dev->queue_lock, lock_flags); + f = list_entry(dev->outqueue.next, + struct em28xx_frame_t, frame); + list_del(dev->outqueue.next); + spin_unlock_irqrestore(&dev->queue_lock, lock_flags); - f->state = F_UNUSED; - memcpy(b, &f->buf, sizeof(*b)); + f->state = F_UNUSED; + memcpy(b, &f->buf, sizeof(*b)); - if (f->vma_use_count) - b->flags |= V4L2_BUF_FLAG_MAPPED; + if (f->vma_use_count) + b->flags |= V4L2_BUF_FLAG_MAPPED; - return 0; - } + return 0; + } default: return em28xx_do_ioctl(inode, filp, dev, cmd, arg, em28xx_video_do_ioctl); @@ -1618,25 +1470,25 @@ static int em28xx_v4l2_ioctl(struct inode *inode, struct file *filp, int ret = 0; struct em28xx *dev = filp->private_data; - if (down_interruptible(&dev->fileop_lock)) + if (mutex_lock_interruptible(&dev->fileop_lock)) return -ERESTARTSYS; if (dev->state & DEV_DISCONNECTED) { em28xx_errdev("v4l2 ioctl: device not present\n"); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -ENODEV; } if (dev->state & DEV_MISCONFIGURED) { em28xx_errdev ("v4l2 ioctl: device is misconfigured; close and open it again\n"); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return -EIO; } ret = video_usercopy(inode, filp, cmd, arg, em28xx_video_do_ioctl); - up(&dev->fileop_lock); + mutex_unlock(&dev->fileop_lock); return ret; } @@ -1670,7 +1522,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->udev = udev; dev->model = model; - init_MUTEX(&dev->lock); + mutex_init(&dev->lock); init_waitqueue_head(&dev->open); dev->em28xx_write_regs = em28xx_write_regs; @@ -1726,10 +1578,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->vpic.depth = 16; dev->vpic.palette = VIDEO_PALETTE_YUV422; + em28xx_pre_card_setup(dev); #ifdef CONFIG_MODULES /* request some modules */ if (dev->decoder == EM28XX_SAA7113 || dev->decoder == EM28XX_SAA7114) - request_module("saa711x"); + request_module("saa7115"); if (dev->decoder == EM28XX_TVP5150) request_module("tvp5150"); if (dev->has_tuner) @@ -1741,10 +1594,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, if (errCode) { em28xx_errdev("error configuring device\n"); kfree(dev); + em28xx_devused&=~(1<<dev->devno); return -ENOMEM; } - down(&dev->lock); + mutex_lock(&dev->lock); /* register i2c bus */ em28xx_i2c_register(dev); @@ -1754,7 +1608,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, /* configure the device */ em28xx_config_i2c(dev); - up(&dev->lock); + mutex_unlock(&dev->lock); errCode = em28xx_config(dev); @@ -1767,9 +1621,30 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, if (NULL == dev->vdev) { em28xx_errdev("cannot allocate video_device.\n"); kfree(dev); + em28xx_devused&=~(1<<dev->devno); return -ENOMEM; } + dev->vbi_dev = video_device_alloc(); + if (NULL == dev->vbi_dev) { + em28xx_errdev("cannot allocate video_device.\n"); + kfree(dev->vdev); + kfree(dev); + em28xx_devused&=~(1<<dev->devno); + return -ENOMEM; + } + + /* Fills VBI device info */ + dev->vbi_dev->type = VFL_TYPE_VBI; + dev->vbi_dev->hardware = 0; + dev->vbi_dev->fops = &em28xx_v4l_fops; + dev->vbi_dev->minor = -1; + dev->vbi_dev->dev = &dev->udev->dev; + dev->vbi_dev->release = video_device_release; + snprintf(dev->vbi_dev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", + "em28xx",dev->devno,"vbi"); + + /* Fills CAPTURE device info */ dev->vdev->type = VID_TYPE_CAPTURE; if (dev->has_tuner) dev->vdev->type |= VID_TYPE_TUNER; @@ -1778,21 +1653,39 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, dev->vdev->minor = -1; dev->vdev->dev = &dev->udev->dev; dev->vdev->release = video_device_release; - snprintf(dev->vdev->name, sizeof(dev->vdev->name), "%s", - "em28xx video"); + snprintf(dev->vdev->name, sizeof(dev->vbi_dev->name), "%s#%d %s", + "em28xx",dev->devno,"video"); + list_add_tail(&dev->devlist,&em28xx_devlist); /* register v4l2 device */ - down(&dev->lock); - if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1))) { + mutex_lock(&dev->lock); + if ((retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, + video_nr[dev->devno]))) { em28xx_errdev("unable to register video device (error=%i).\n", retval); - up(&dev->lock); + mutex_unlock(&dev->lock); list_del(&dev->devlist); video_device_release(dev->vdev); kfree(dev); + em28xx_devused&=~(1<<dev->devno); return -ENODEV; } + + if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, + vbi_nr[dev->devno]) < 0) { + printk("unable to register vbi device\n"); + mutex_unlock(&dev->lock); + list_del(&dev->devlist); + video_device_release(dev->vbi_dev); + video_device_release(dev->vdev); + kfree(dev); + em28xx_devused&=~(1<<dev->devno); + return -ENODEV; + } else { + printk("registered VBI\n"); + } + if (dev->has_msp34xx) { /* Send a reset to other chips via gpio */ em28xx_write_regs_req(dev, 0x00, 0x08, "\xf7", 1); @@ -1803,10 +1696,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, } video_mux(dev, 0); - up(&dev->lock); + mutex_unlock(&dev->lock); - em28xx_info("V4L2 device registered as /dev/video%d\n", - dev->vdev->minor); + 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); return 0; } @@ -1828,6 +1722,9 @@ static int em28xx_usb_probe(struct usb_interface *interface, 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) { @@ -1835,6 +1732,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, udev->descriptor.idVendor,udev->descriptor.idProduct, ifnum, interface->altsetting[0].desc.bInterfaceClass); + + em28xx_devused&=~(1<<nr); return -ENODEV; } @@ -1849,18 +1748,20 @@ static int em28xx_usb_probe(struct usb_interface *interface, 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; } model=id->driver_info; - nr=interface->minor; - if (nr>EM28XX_MAXBOARDS) { + if (nr >= EM28XX_MAXBOARDS) { printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS); + em28xx_devused&=~(1<<nr); return -ENOMEM; } @@ -1868,19 +1769,24 @@ static int em28xx_usb_probe(struct usb_interface *interface, 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; + /* compute alternate max packet sizes */ uif = udev->actconfig->interface[0]; dev->num_alt=uif->num_altsetting; - printk(DRIVER_NAME ": Alternate settings: %i\n",dev->num_alt); + 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_err(DRIVER_NAME ": out of memory!\n"); + em28xx_errdev("out of memory!\n"); + em28xx_devused&=~(1<<nr); return -ENOMEM; } @@ -1889,27 +1795,26 @@ static int em28xx_usb_probe(struct usb_interface *interface, wMaxPacketSize); dev->alt_max_pkt_size[i] = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); - printk(DRIVER_NAME ": Alternate setting %i, max size= %i\n",i, + em28xx_info("Alternate setting %i, max size= %i\n",i, dev->alt_max_pkt_size[i]); } - snprintf(dev->name, 29, "em28xx #%d", nr); - if ((card[nr]>=0)&&(card[nr]<em28xx_bcount)) model=card[nr]; if ((model==EM2800_BOARD_UNKNOWN)||(model==EM2820_BOARD_UNKNOWN)) { - printk( "%s: Your board has no eeprom inside it and thus can't\n" + em28xx_errdev( "Your board has no eeprom inside it and thus can't\n" "%s: be autodetected. Please pass card=<n> insmod option to\n" "%s: workaround that. Redirect complaints to the vendor of\n" - "%s: the TV card. Best regards,\n" + "%s: the TV card. Generic type will be used." + "%s: Best regards,\n" "%s: -- tux\n", dev->name,dev->name,dev->name,dev->name,dev->name); - printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n", + em28xx_errdev("%s: Here is a list of valid choices for the card=<n> insmod option:\n", dev->name); for (i = 0; i < em28xx_bcount; i++) { - printk("%s: card=%d -> %s\n", - dev->name, i, em28xx_boards[i].name); + em28xx_errdev(" card=%d -> %s\n", i, + em28xx_boards[i].name); } } @@ -1935,15 +1840,12 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) struct em28xx *dev = usb_get_intfdata(interface); usb_set_intfdata(interface, NULL); -/*FIXME: IR should be disconnected */ - if (!dev) return; - down_write(&em28xx_disconnect); - down(&dev->lock); + mutex_lock(&dev->lock); em28xx_info("disconnecting %s\n", dev->vdev->name); @@ -1952,7 +1854,9 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) if (dev->users) { em28xx_warn ("device /dev/video%d is open! Deregistration and memory " - "deallocation are deferred on close.\n", dev->vdev->minor); + "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; @@ -1963,7 +1867,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) em28xx_release_resources(dev); } - up(&dev->lock); + mutex_unlock(&dev->lock); if (!dev->users) { kfree(dev->alt_max_pkt_size); diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h index 33de9d846af..e1ddc2f27a2 100644 --- a/drivers/media/video/em28xx/em28xx.h +++ b/drivers/media/video/em28xx/em28xx.h @@ -27,6 +27,7 @@ #include <linux/videodev.h> #include <linux/i2c.h> +#include <linux/mutex.h> #include <media/ir-kbd-i2c.h> /* Boards supported by driver */ @@ -41,6 +42,10 @@ #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 UNSET -1 @@ -209,6 +214,7 @@ 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; int video_inputs; /* number of video inputs */ struct list_head devlist; @@ -256,7 +262,7 @@ struct em28xx { enum em28xx_stream_state stream; enum em28xx_io_method io; /* locks */ - struct semaphore lock, fileop_lock; + struct mutex lock, fileop_lock; spinlock_t queue_lock; struct list_head inqueue, outqueue; wait_queue_head_t open, wait_frame, wait_stream; @@ -326,6 +332,7 @@ int em28xx_set_alternate(struct em28xx *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[]; diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c index e7bbeb11553..c7fed340565 100644 --- a/drivers/media/video/hexium_gemini.c +++ b/drivers/media/video/hexium_gemini.c @@ -1,9 +1,9 @@ /* hexium_gemini.c - v4l2 driver for Hexium Gemini frame grabber cards - + Visit http://www.mihu.de/linux/saa7146/ and follow the link to "hexium" for further details about this card. - + Copyright (C) 2003 Michael Hunold <michael@mihu.de> This program is free software; you can redistribute it and/or modify @@ -81,7 +81,7 @@ struct hexium struct video_device *video_dev; struct i2c_adapter i2c_adapter; - + int cur_input; /* current input */ v4l2_std_id cur_std; /* current standard */ int cur_bw; /* current black/white status */ @@ -174,7 +174,7 @@ static struct saa7146_standard hexium_standards[] = { .h_offset = 1, .h_pixels = 720, .v_max_out = 576, .h_max_out = 768, } -}; +}; /* bring hardware to a sane state. this has to be done, just in case someone wants to capture from this device before it has been properly initialized. @@ -311,7 +311,7 @@ static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) struct saa7146_dev *dev = fh->dev; struct hexium *hexium = (struct hexium *) dev->ext_priv; /* - struct saa7146_vv *vv = dev->vv_data; + struct saa7146_vv *vv = dev->vv_data; */ switch (cmd) { case VIDIOC_ENUMINPUT: diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c index aad4a18aafd..137c4736da0 100644 --- a/drivers/media/video/hexium_orion.c +++ b/drivers/media/video/hexium_orion.c @@ -3,7 +3,7 @@ Visit http://www.mihu.de/linux/saa7146/ and follow the link to "hexium" for further details about this card. - + Copyright (C) 2003 Michael Hunold <michael@mihu.de> This program is free software; you can redistribute it and/or modify @@ -69,7 +69,7 @@ struct hexium { int type; struct video_device *video_dev; - struct i2c_adapter i2c_adapter; + struct i2c_adapter i2c_adapter; int cur_input; /* current input */ }; @@ -86,7 +86,7 @@ static u8 hexium_saa7110[53]={ }; static struct { - struct hexium_data data[8]; + struct hexium_data data[8]; } hexium_input_select[] = { { { /* cvbs 1 */ @@ -153,7 +153,7 @@ static struct { { 0x30, 0x60 }, { 0x31, 0xB5 }, // ?? { 0x21, 0x03 }, - } + } }, { { /* y/c 1 */ { 0x06, 0x80 }, @@ -187,7 +187,7 @@ static struct { { 0x31, 0x75 }, { 0x21, 0x21 }, } -} +} }; static struct saa7146_standard hexium_standards[] = { @@ -207,7 +207,7 @@ static struct saa7146_standard hexium_standards[] = { .h_offset = 1, .h_pixels = 720, .v_max_out = 576, .h_max_out = 768, } -}; +}; /* this is only called for old HV-PCI6/Orion cards without eeprom */ @@ -272,7 +272,7 @@ static int hexium_probe(struct saa7146_dev *dev) return 0; } - /* check if this is an old hexium Orion card by looking at + /* check if this is an old hexium Orion card by looking at a saa7110 at address 0x4e */ if (0 == (err = i2c_smbus_xfer(&hexium->i2c_adapter, 0x4e, 0, I2C_SMBUS_READ, 0x00, I2C_SMBUS_BYTE_DATA, &data))) { printk("hexium_orion: device is a Hexium HV-PCI6/Orion (old).\n"); @@ -314,7 +314,7 @@ static int hexium_set_input(struct hexium *hexium, int input) { union i2c_smbus_data data; int i = 0; - + DEB_D((".\n")); for (i = 0; i < 8; i++) { @@ -375,7 +375,7 @@ static int hexium_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) struct saa7146_dev *dev = fh->dev; struct hexium *hexium = (struct hexium *) dev->ext_priv; /* - struct saa7146_vv *vv = dev->vv_data; + struct saa7146_vv *vv = dev->vv_data; */ switch (cmd) { case VIDIOC_ENUMINPUT: diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c index 58b0e698282..95bacf43541 100644 --- a/drivers/media/video/ir-kbd-i2c.c +++ b/drivers/media/video/ir-kbd-i2c.c @@ -44,51 +44,17 @@ #include <media/ir-common.h> #include <media/ir-kbd-i2c.h> -/* Mark Phalan <phalanm@o2.ie> */ -static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = { - [ 0 ] = KEY_KP0, - [ 1 ] = KEY_KP1, - [ 2 ] = KEY_KP2, - [ 3 ] = KEY_KP3, - [ 4 ] = KEY_KP4, - [ 5 ] = KEY_KP5, - [ 6 ] = KEY_KP6, - [ 7 ] = KEY_KP7, - [ 8 ] = KEY_KP8, - [ 9 ] = KEY_KP9, - - [ 18 ] = KEY_POWER, - [ 16 ] = KEY_MUTE, - [ 31 ] = KEY_VOLUMEDOWN, - [ 27 ] = KEY_VOLUMEUP, - [ 26 ] = KEY_CHANNELUP, - [ 30 ] = KEY_CHANNELDOWN, - [ 14 ] = KEY_PAGEUP, - [ 29 ] = KEY_PAGEDOWN, - [ 19 ] = KEY_SOUND, - - [ 24 ] = KEY_KPPLUSMINUS, /* CH +/- */ - [ 22 ] = KEY_SUBTITLE, /* CC */ - [ 13 ] = KEY_TEXT, /* TTX */ - [ 11 ] = KEY_TV, /* AIR/CBL */ - [ 17 ] = KEY_PC, /* PC/TV */ - [ 23 ] = KEY_OK, /* CH RTN */ - [ 25 ] = KEY_MODE, /* FUNC */ - [ 12 ] = KEY_SEARCH, /* AUTOSCAN */ - - /* Not sure what to do with these ones! */ - [ 15 ] = KEY_SELECT, /* SOURCE */ - [ 10 ] = KEY_KPPLUS, /* +100 */ - [ 20 ] = KEY_KPEQUAL, /* SYNC */ - [ 28 ] = KEY_MEDIA, /* PC/TV */ -}; - /* ----------------------------------------------------------------------- */ /* insmod parameters */ static int debug; module_param(debug, int, 0644); /* debug level (0,1,2) */ +static int hauppauge = 0; +module_param(hauppauge, int, 0644); /* Choose Hauppauge remote */ +MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults to 0)"); + + #define DEVNAME "ir-kbd-i2c" #define dprintk(level, fmt, arg...) if (debug >= level) \ printk(KERN_DEBUG DEVNAME ": " fmt , ## arg) @@ -336,7 +302,11 @@ static int ir_attach(struct i2c_adapter *adap, int addr, name = "Hauppauge"; ir->get_key = get_key_haup; ir_type = IR_TYPE_RC5; - ir_codes = ir_codes_rc5_tv; + if (hauppauge == 1) { + ir_codes = ir_codes_hauppauge_new; + } else { + ir_codes = ir_codes_rc5_tv; + } break; case 0x30: name = "KNC One"; diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c index 2869464aee0..850bee97090 100644 --- a/drivers/media/video/meye.c +++ b/drivers/media/video/meye.c @@ -925,7 +925,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; if (p->palette != VIDEO_PALETTE_YUV422) return -EINVAL; - down(&meye.lock); + mutex_lock(&meye.lock); sonypi_camera_command(SONYPI_COMMAND_SETCAMERABRIGHTNESS, p->brightness >> 10); sonypi_camera_command(SONYPI_COMMAND_SETCAMERAHUE, @@ -935,7 +935,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, sonypi_camera_command(SONYPI_COMMAND_SETCAMERACONTRAST, p->contrast >> 10); meye.picture = *p; - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -946,21 +946,21 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, if (*i < 0 || *i >= gbuffers) return -EINVAL; - down(&meye.lock); + mutex_lock(&meye.lock); switch (meye.grab_buffer[*i].state) { case MEYE_BUF_UNUSED: - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINVAL; case MEYE_BUF_USING: if (file->f_flags & O_NONBLOCK) { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EAGAIN; } if (wait_event_interruptible(meye.proc_list, (meye.grab_buffer[*i].state != MEYE_BUF_USING))) { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINTR; } /* fall through */ @@ -968,7 +968,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, meye.grab_buffer[*i].state = MEYE_BUF_UNUSED; kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int)); } - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -987,7 +987,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED) return -EBUSY; - down(&meye.lock); + mutex_lock(&meye.lock); if (vm->width == 640 && vm->height == 480) { if (meye.params.subsample) { meye.params.subsample = 0; @@ -999,7 +999,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, restart = 1; } } else { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINVAL; } @@ -1007,7 +1007,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, mchip_continuous_start(); meye.grab_buffer[vm->frame].state = MEYE_BUF_USING; kfifo_put(meye.grabq, (unsigned char *)&vm->frame, sizeof(int)); - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -1039,7 +1039,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; if (jp->framerate > 31) return -EINVAL; - down(&meye.lock); + mutex_lock(&meye.lock); if (meye.params.subsample != jp->subsample || meye.params.quality != jp->quality) mchip_hic_stop(); /* need restart */ @@ -1050,7 +1050,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, meye.params.agc); sonypi_camera_command(SONYPI_COMMAND_SETCAMERAPICTURE, meye.params.picture); - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -1068,12 +1068,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, } if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED) return -EBUSY; - down(&meye.lock); + mutex_lock(&meye.lock); if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP) mchip_cont_compression_start(); meye.grab_buffer[*nb].state = MEYE_BUF_USING; kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int)); - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -1084,20 +1084,20 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, if (*i < 0 || *i >= gbuffers) return -EINVAL; - down(&meye.lock); + mutex_lock(&meye.lock); switch (meye.grab_buffer[*i].state) { case MEYE_BUF_UNUSED: - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINVAL; case MEYE_BUF_USING: if (file->f_flags & O_NONBLOCK) { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EAGAIN; } if (wait_event_interruptible(meye.proc_list, (meye.grab_buffer[*i].state != MEYE_BUF_USING))) { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINTR; } /* fall through */ @@ -1106,7 +1106,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int)); } *i = meye.grab_buffer[*i].size; - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -1116,14 +1116,14 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) return -EBUSY; - down(&meye.lock); + mutex_lock(&meye.lock); meye.grab_buffer[0].state = MEYE_BUF_USING; mchip_take_picture(); mchip_get_picture( meye.grab_fbuffer, mchip_hsize() * mchip_vsize() * 2); meye.grab_buffer[0].state = MEYE_BUF_DONE; - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -1134,7 +1134,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED) return -EBUSY; - down(&meye.lock); + mutex_lock(&meye.lock); meye.grab_buffer[0].state = MEYE_BUF_USING; *len = -1; while (*len == -1) { @@ -1142,7 +1142,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize); } meye.grab_buffer[0].state = MEYE_BUF_DONE; - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -1285,7 +1285,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_S_CTRL: { struct v4l2_control *c = arg; - down(&meye.lock); + mutex_lock(&meye.lock); switch (c->id) { case V4L2_CID_BRIGHTNESS: sonypi_camera_command( @@ -1329,17 +1329,17 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, meye.params.framerate = c->value; break; default: - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINVAL; } - up(&meye.lock); + mutex_unlock(&meye.lock); break; } case VIDIOC_G_CTRL: { struct v4l2_control *c = arg; - down(&meye.lock); + mutex_lock(&meye.lock); switch (c->id) { case V4L2_CID_BRIGHTNESS: c->value = meye.picture.brightness >> 10; @@ -1369,10 +1369,10 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, c->value = meye.params.framerate; break; default: - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINVAL; } - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -1469,7 +1469,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, f->fmt.pix.field != V4L2_FIELD_NONE) return -EINVAL; f->fmt.pix.field = V4L2_FIELD_NONE; - down(&meye.lock); + mutex_lock(&meye.lock); if (f->fmt.pix.width <= 320) { f->fmt.pix.width = 320; f->fmt.pix.height = 240; @@ -1487,7 +1487,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP; break; } - up(&meye.lock); + mutex_unlock(&meye.lock); f->fmt.pix.bytesperline = f->fmt.pix.width * 2; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; @@ -1509,11 +1509,11 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, /* already allocated, no modifications */ break; } - down(&meye.lock); + mutex_lock(&meye.lock); if (meye.grab_fbuffer) { for (i = 0; i < gbuffers; i++) if (meye.vma_use_count[i]) { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINVAL; } rvfree(meye.grab_fbuffer, gbuffers * gbufsize); @@ -1525,12 +1525,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, if (!meye.grab_fbuffer) { printk(KERN_ERR "meye: v4l framebuffer allocation" " failed\n"); - up(&meye.lock); + mutex_unlock(&meye.lock); return -ENOMEM; } for (i = 0; i < gbuffers; i++) meye.vma_use_count[i] = 0; - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -1569,12 +1569,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED) return -EINVAL; - down(&meye.lock); + mutex_lock(&meye.lock); buf->flags |= V4L2_BUF_FLAG_QUEUED; buf->flags &= ~V4L2_BUF_FLAG_DONE; meye.grab_buffer[buf->index].state = MEYE_BUF_USING; kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int)); - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -1587,23 +1587,23 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, if (buf->memory != V4L2_MEMORY_MMAP) return -EINVAL; - down(&meye.lock); + mutex_lock(&meye.lock); if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EAGAIN; } if (wait_event_interruptible(meye.proc_list, kfifo_len(meye.doneq) != 0) < 0) { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINTR; } if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr, sizeof(int))) { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EBUSY; } if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINVAL; } buf->index = reqnr; @@ -1616,12 +1616,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, buf->m.offset = reqnr * gbufsize; buf->length = gbufsize; meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED; - up(&meye.lock); + mutex_unlock(&meye.lock); break; } case VIDIOC_STREAMON: { - down(&meye.lock); + mutex_lock(&meye.lock); switch (meye.mchip_mode) { case MCHIP_HIC_MODE_CONT_OUT: mchip_continuous_start(); @@ -1630,23 +1630,23 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, mchip_cont_compression_start(); break; default: - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINVAL; } - up(&meye.lock); + mutex_unlock(&meye.lock); break; } case VIDIOC_STREAMOFF: { int i; - down(&meye.lock); + mutex_lock(&meye.lock); mchip_hic_stop(); kfifo_reset(meye.grabq); kfifo_reset(meye.doneq); for (i = 0; i < MEYE_MAX_BUFNBRS; i++) meye.grab_buffer[i].state = MEYE_BUF_UNUSED; - up(&meye.lock); + mutex_unlock(&meye.lock); break; } @@ -1672,11 +1672,11 @@ static unsigned int meye_poll(struct file *file, poll_table *wait) { unsigned int res = 0; - down(&meye.lock); + mutex_lock(&meye.lock); poll_wait(file, &meye.proc_list, wait); if (kfifo_len(meye.doneq)) res = POLLIN | POLLRDNORM; - up(&meye.lock); + mutex_unlock(&meye.lock); return res; } @@ -1704,9 +1704,9 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma) unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; unsigned long page, pos; - down(&meye.lock); + mutex_lock(&meye.lock); if (size > gbuffers * gbufsize) { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EINVAL; } if (!meye.grab_fbuffer) { @@ -1716,7 +1716,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma) meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize); if (!meye.grab_fbuffer) { printk(KERN_ERR "meye: v4l framebuffer allocation failed\n"); - up(&meye.lock); + mutex_unlock(&meye.lock); return -ENOMEM; } for (i = 0; i < gbuffers; i++) @@ -1727,7 +1727,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma) while (size > 0) { page = vmalloc_to_pfn((void *)pos); if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - up(&meye.lock); + mutex_unlock(&meye.lock); return -EAGAIN; } start += PAGE_SIZE; @@ -1744,7 +1744,7 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma) vma->vm_private_data = (void *) (offset / gbufsize); meye_vm_open(vma); - up(&meye.lock); + mutex_unlock(&meye.lock); return 0; } @@ -1913,7 +1913,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev, goto outvideoreg; } - init_MUTEX(&meye.lock); + mutex_init(&meye.lock); init_waitqueue_head(&meye.proc_list); meye.picture.depth = 16; meye.picture.palette = VIDEO_PALETTE_YUV422; diff --git a/drivers/media/video/meye.h b/drivers/media/video/meye.h index e8cd897b0d2..0d09a0e3803 100644 --- a/drivers/media/video/meye.h +++ b/drivers/media/video/meye.h @@ -260,6 +260,8 @@ /* private API definitions */ #include <linux/meye.h> +#include <linux/mutex.h> + /* Enable jpg software correction */ #define MEYE_JPEG_CORRECTION 1 @@ -301,7 +303,7 @@ struct meye { /* list of buffers */ struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */ - struct semaphore lock; /* semaphore for open/mmap... */ + struct mutex lock; /* mutex for open/mmap... */ struct kfifo *grabq; /* queue for buffers to be grabbed */ spinlock_t grabq_lock; /* lock protecting the queue */ struct kfifo *doneq; /* queue for grabbed buffers */ diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c index 69ed369c2f4..11ea9765769 100644 --- a/drivers/media/video/msp3400-driver.c +++ b/drivers/media/video/msp3400-driver.c @@ -411,9 +411,9 @@ static int msp_mode_v4l2_to_v4l1(int rxsubchans) if (rxsubchans & V4L2_TUNER_SUB_STEREO) mode |= VIDEO_SOUND_STEREO; if (rxsubchans & V4L2_TUNER_SUB_LANG2) - mode |= VIDEO_SOUND_LANG2; + mode |= VIDEO_SOUND_LANG2 | VIDEO_SOUND_STEREO; if (rxsubchans & V4L2_TUNER_SUB_LANG1) - mode |= VIDEO_SOUND_LANG1; + mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_STEREO; if (mode == 0) mode |= VIDEO_SOUND_MONO; return mode; @@ -430,21 +430,6 @@ static int msp_mode_v4l1_to_v4l2(int mode) return V4L2_TUNER_MODE_MONO; } -static void msp_any_detect_stereo(struct i2c_client *client) -{ - struct msp_state *state = i2c_get_clientdata(client); - - switch (state->opmode) { - case OPMODE_MANUAL: - case OPMODE_AUTODETECT: - autodetect_stereo(client); - break; - case OPMODE_AUTOSELECT: - msp34xxg_detect_stereo(client); - break; - } -} - static struct v4l2_queryctrl msp_qctrl_std[] = { { .id = V4L2_CID_AUDIO_VOLUME, @@ -506,22 +491,6 @@ static struct v4l2_queryctrl msp_qctrl_sound_processing[] = { }; -static void msp_any_set_audmode(struct i2c_client *client, int audmode) -{ - struct msp_state *state = i2c_get_clientdata(client); - - switch (state->opmode) { - case OPMODE_MANUAL: - case OPMODE_AUTODETECT: - state->watch_stereo = 0; - msp3400c_setstereo(client, audmode); - break; - case OPMODE_AUTOSELECT: - msp34xxg_set_audmode(client, audmode); - break; - } -} - static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) { struct msp_state *state = i2c_get_clientdata(client); @@ -653,11 +622,10 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) } if (scart) { state->rxsubchans = V4L2_TUNER_SUB_STEREO; - state->audmode = V4L2_TUNER_MODE_STEREO; msp_set_scart(client, scart, 0); msp_write_dsp(client, 0x000d, 0x1900); if (state->opmode != OPMODE_AUTOSELECT) - msp3400c_setstereo(client, state->audmode); + msp_set_audmode(client); } msp_wake_thread(client); break; @@ -671,8 +639,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) switch (state->opmode) { case OPMODE_MANUAL: /* set msp3400 to FM radio mode */ - msp3400c_setmode(client, MSP_MODE_FM_RADIO); - msp3400c_setcarrier(client, MSP_CARRIER(10.7), + msp3400c_set_mode(client, MSP_MODE_FM_RADIO); + msp3400c_set_carrier(client, MSP_CARRIER(10.7), MSP_CARRIER(10.7)); msp_set_audio(client); break; @@ -706,7 +674,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) if (state->radio) break; if (state->opmode == OPMODE_AUTOSELECT) - msp_any_detect_stereo(client); + msp_detect_stereo(client); va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans); break; } @@ -722,8 +690,9 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) state->treble = va->treble; msp_set_audio(client); - if (va->mode != 0 && state->radio == 0) - msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode)); + if (va->mode != 0 && state->radio == 0) { + state->audmode = msp_mode_v4l1_to_v4l2(va->mode); + } break; } @@ -831,11 +800,8 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) return -EINVAL; } - msp_any_detect_stereo(client); - if (state->audmode == V4L2_TUNER_MODE_STEREO) { - a->capability = V4L2_AUDCAP_STEREO; - } - + a->capability = V4L2_AUDCAP_STEREO; + a->mode = 0; /* TODO: add support for AVL */ break; } @@ -865,16 +831,10 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) } if (scart) { state->rxsubchans = V4L2_TUNER_SUB_STEREO; - state->audmode = V4L2_TUNER_MODE_STEREO; msp_set_scart(client, scart, 0); msp_write_dsp(client, 0x000d, 0x1900); } - if (sarg->capability == V4L2_AUDCAP_STEREO) { - state->audmode = V4L2_TUNER_MODE_STEREO; - } else { - state->audmode &= ~V4L2_TUNER_MODE_STEREO; - } - msp_any_set_audmode(client, state->audmode); + msp_set_audmode(client); msp_wake_thread(client); break; } @@ -886,7 +846,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) if (state->radio) break; if (state->opmode == OPMODE_AUTOSELECT) - msp_any_detect_stereo(client); + msp_detect_stereo(client); vt->audmode = state->audmode; vt->rxsubchans = state->rxsubchans; vt->capability = V4L2_TUNER_CAP_STEREO | @@ -898,11 +858,11 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; - if (state->radio) + if (state->radio) /* TODO: add mono/stereo support for radio */ break; + state->audmode = vt->audmode; /* only set audmode */ - if (vt->audmode != -1 && vt->audmode != 0) - msp_any_set_audmode(client, vt->audmode); + msp_set_audmode(client); break; } @@ -927,7 +887,6 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) return -EINVAL; } break; - } case VIDIOC_S_AUDOUT: @@ -993,7 +952,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) const char *p; if (state->opmode == OPMODE_AUTOSELECT) - msp_any_detect_stereo(client); + msp_detect_stereo(client); v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", client->name, state->rev1, state->rev2); v4l_info(client, "Audio: volume %d%s\n", @@ -1094,6 +1053,7 @@ static int msp_attach(struct i2c_adapter *adapter, int address, int kind) memset(state, 0, sizeof(*state)); state->v4l2_std = V4L2_STD_NTSC; + state->audmode = V4L2_TUNER_MODE_LANG1; state->volume = 58880; /* 0db gain */ state->balance = 32768; /* 0db gain */ state->bass = 32768; diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c index 2072c3efebb..852ab6a115f 100644 --- a/drivers/media/video/msp3400-kthreads.c +++ b/drivers/media/video/msp3400-kthreads.c @@ -109,7 +109,7 @@ static struct msp3400c_init_data_dem { {-2, -8, -10, 10, 50, 86}, {-4, -12, -9, 23, 79, 126}, MSP_CARRIER(6.5), MSP_CARRIER(6.5), - 0x00c6, 0x0140, 0x0120, 0x7c03 + 0x00c6, 0x0140, 0x0120, 0x7c00 }, }; @@ -154,54 +154,60 @@ const char *msp_standard_std_name(int std) return "unknown"; } -void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) +static void msp_set_source(struct i2c_client *client, u16 src) +{ + struct msp_state *state = i2c_get_clientdata(client); + + if (msp_dolby) { + msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */ + msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */ + } else { + msp_write_dsp(client, 0x0008, src); + msp_write_dsp(client, 0x0009, src); + } + msp_write_dsp(client, 0x000a, src); + msp_write_dsp(client, 0x000b, src); + msp_write_dsp(client, 0x000c, src); + if (state->has_scart23_in_scart2_out) + msp_write_dsp(client, 0x0041, src); +} + +void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2) { msp_write_dem(client, 0x0093, cdo1 & 0xfff); msp_write_dem(client, 0x009b, cdo1 >> 12); msp_write_dem(client, 0x00a3, cdo2 & 0xfff); msp_write_dem(client, 0x00ab, cdo2 >> 12); - msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ + msp_write_dem(client, 0x0056, 0); /* LOAD_REG_1/2 */ } -void msp3400c_setmode(struct i2c_client *client, int type) +void msp3400c_set_mode(struct i2c_client *client, int mode) { struct msp_state *state = i2c_get_clientdata(client); + struct msp3400c_init_data_dem *data = &msp3400c_init_data[mode]; int i; - v4l_dbg(1, msp_debug, client, "setmode: %d\n", type); - state->mode = type; - state->audmode = V4L2_TUNER_MODE_MONO; + v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode); + state->mode = mode; state->rxsubchans = V4L2_TUNER_SUB_MONO; - msp_write_dem(client, 0x00bb, msp3400c_init_data[type].ad_cv); + msp_write_dem(client, 0x00bb, data->ad_cv); for (i = 5; i >= 0; i--) /* fir 1 */ - msp_write_dem(client, 0x0001, msp3400c_init_data[type].fir1[i]); + msp_write_dem(client, 0x0001, data->fir1[i]); msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */ msp_write_dem(client, 0x0005, 0x0040); msp_write_dem(client, 0x0005, 0x0000); for (i = 5; i >= 0; i--) - msp_write_dem(client, 0x0005, msp3400c_init_data[type].fir2[i]); + msp_write_dem(client, 0x0005, data->fir2[i]); - msp_write_dem(client, 0x0083, msp3400c_init_data[type].mode_reg); + msp_write_dem(client, 0x0083, data->mode_reg); - msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1, - msp3400c_init_data[type].cdo2); + msp3400c_set_carrier(client, data->cdo1, data->cdo2); - msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ - - if (msp_dolby) { - msp_write_dsp(client, 0x0008, 0x0520); /* I2S1 */ - msp_write_dsp(client, 0x0009, 0x0620); /* I2S2 */ - msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src); - } else { - msp_write_dsp(client, 0x0008, msp3400c_init_data[type].dsp_src); - msp_write_dsp(client, 0x0009, msp3400c_init_data[type].dsp_src); - msp_write_dsp(client, 0x000b, msp3400c_init_data[type].dsp_src); - } - msp_write_dsp(client, 0x000a, msp3400c_init_data[type].dsp_src); - msp_write_dsp(client, 0x000e, msp3400c_init_data[type].dsp_matrix); + msp_set_source(client, data->dsp_src); + msp_write_dsp(client, 0x000e, data->dsp_matrix); if (state->has_nicam) { /* nicam prescale */ @@ -209,29 +215,31 @@ void msp3400c_setmode(struct i2c_client *client, int type) } } -/* turn on/off nicam + stereo */ -void msp3400c_setstereo(struct i2c_client *client, int mode) +/* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP, + nor do they support stereo BTSC. */ +static void msp3400c_set_audmode(struct i2c_client *client) { static char *strmode[] = { "mono", "stereo", "lang2", "lang1" }; struct msp_state *state = i2c_get_clientdata(client); - int nicam = 0; /* channel source: FM/AM or nicam */ - int src = 0; + char *modestr = (state->audmode >= 0 && state->audmode < 4) ? + strmode[state->audmode] : "unknown"; + int src = 0; /* channel source: FM/AM, nicam or SCART */ if (state->opmode == OPMODE_AUTOSELECT) { /* this method would break everything, let's make sure * it's never called */ - v4l_dbg(1, msp_debug, client, "setstereo called with mode=%d instead of set_source (ignored)\n", - mode); + v4l_dbg(1, msp_debug, client, + "set_audmode called with mode=%d instead of set_source (ignored)\n", + state->audmode); return; } /* switch demodulator */ switch (state->mode) { case MSP_MODE_FM_TERRA: - v4l_dbg(1, msp_debug, client, "FM setstereo: %s\n", strmode[mode]); - msp3400c_setcarrier(client, state->second, state->main); - switch (mode) { + v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr); + switch (state->audmode) { case V4L2_TUNER_MODE_STEREO: msp_write_dsp(client, 0x000e, 0x3001); break; @@ -243,50 +251,49 @@ void msp3400c_setstereo(struct i2c_client *client, int mode) } break; case MSP_MODE_FM_SAT: - v4l_dbg(1, msp_debug, client, "SAT setstereo: %s\n", strmode[mode]); - switch (mode) { + v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr); + switch (state->audmode) { case V4L2_TUNER_MODE_MONO: - msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); + msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); break; case V4L2_TUNER_MODE_STEREO: - msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); + msp3400c_set_carrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); break; case V4L2_TUNER_MODE_LANG1: - msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); break; case V4L2_TUNER_MODE_LANG2: - msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); + msp3400c_set_carrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); break; } break; case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM: - v4l_dbg(1, msp_debug, client, "NICAM setstereo: %s\n",strmode[mode]); - msp3400c_setcarrier(client,state->second,state->main); + v4l_dbg(1, msp_debug, client, "NICAM set_audmode: %s\n",modestr); + msp3400c_set_carrier(client, state->second, state->main); if (state->nicam_on) - nicam=0x0100; + src = 0x0100; /* NICAM */ break; case MSP_MODE_BTSC: - v4l_dbg(1, msp_debug, client, "BTSC setstereo: %s\n",strmode[mode]); - nicam=0x0300; + v4l_dbg(1, msp_debug, client, "BTSC set_audmode: %s\n",modestr); break; case MSP_MODE_EXTERN: - v4l_dbg(1, msp_debug, client, "extern setstereo: %s\n",strmode[mode]); - nicam = 0x0200; + v4l_dbg(1, msp_debug, client, "extern set_audmode: %s\n",modestr); + src = 0x0200; /* SCART */ break; case MSP_MODE_FM_RADIO: - v4l_dbg(1, msp_debug, client, "FM-Radio setstereo: %s\n",strmode[mode]); + v4l_dbg(1, msp_debug, client, "FM-Radio set_audmode: %s\n",modestr); break; default: - v4l_dbg(1, msp_debug, client, "mono setstereo\n"); + v4l_dbg(1, msp_debug, client, "mono set_audmode\n"); return; } /* switch audio */ - switch (mode) { + switch (state->audmode) { case V4L2_TUNER_MODE_STEREO: - src = 0x0020 | nicam; + src |= 0x0020; break; case V4L2_TUNER_MODE_MONO: if (state->mode == MSP_MODE_AM_NICAM) { @@ -297,29 +304,22 @@ void msp3400c_setstereo(struct i2c_client *client, int mode) src = 0x0200; break; } + if (state->rxsubchans & V4L2_TUNER_SUB_STEREO) + src = 0x0030; + break; case V4L2_TUNER_MODE_LANG1: - src = 0x0000 | nicam; + /* switch to stereo for stereo transmission, otherwise + keep first language */ + if (state->rxsubchans & V4L2_TUNER_SUB_STEREO) + src |= 0x0020; break; case V4L2_TUNER_MODE_LANG2: - src = 0x0010 | nicam; + src |= 0x0010; break; } - v4l_dbg(1, msp_debug, client, "setstereo final source/matrix = 0x%x\n", src); + v4l_dbg(1, msp_debug, client, "set_audmode final source/matrix = 0x%x\n", src); - if (msp_dolby) { - msp_write_dsp(client, 0x0008, 0x0520); - msp_write_dsp(client, 0x0009, 0x0620); - msp_write_dsp(client, 0x000a, src); - msp_write_dsp(client, 0x000b, src); - } else { - msp_write_dsp(client, 0x0008, src); - msp_write_dsp(client, 0x0009, src); - msp_write_dsp(client, 0x000a, src); - msp_write_dsp(client, 0x000b, src); - msp_write_dsp(client, 0x000c, src); - if (state->has_scart23_in_scart2_out) - msp_write_dsp(client, 0x0041, src); - } + msp_set_source(client, src); } static void msp3400c_print_mode(struct i2c_client *client) @@ -347,12 +347,12 @@ static void msp3400c_print_mode(struct i2c_client *client) /* ----------------------------------------------------------------------- */ -int autodetect_stereo(struct i2c_client *client) +static int msp3400c_detect_stereo(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); int val; int rxsubchans = state->rxsubchans; - int newnicam = state->nicam_on; + int newnicam = state->nicam_on; int update = 0; switch (state->mode) { @@ -362,7 +362,7 @@ int autodetect_stereo(struct i2c_client *client) val -= 65536; v4l_dbg(2, msp_debug, client, "stereo detect register: %d\n", val); if (val > 4096) { - rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; + rxsubchans = V4L2_TUNER_SUB_STEREO; } else if (val < -4096) { rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; } else { @@ -386,14 +386,11 @@ int autodetect_stereo(struct i2c_client *client) break; case 1: case 9: - rxsubchans = V4L2_TUNER_SUB_MONO - | V4L2_TUNER_SUB_LANG1; + rxsubchans = V4L2_TUNER_SUB_MONO; break; case 2: case 10: - rxsubchans = V4L2_TUNER_SUB_MONO - | V4L2_TUNER_SUB_LANG1 - | V4L2_TUNER_SUB_LANG2; + rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; break; default: rxsubchans = V4L2_TUNER_SUB_MONO; @@ -405,30 +402,17 @@ int autodetect_stereo(struct i2c_client *client) rxsubchans = V4L2_TUNER_SUB_MONO; } break; - case MSP_MODE_BTSC: - val = msp_read_dem(client, 0x200); - v4l_dbg(2, msp_debug, client, "status=0x%x (pri=%s, sec=%s, %s%s%s)\n", - val, - (val & 0x0002) ? "no" : "yes", - (val & 0x0004) ? "no" : "yes", - (val & 0x0040) ? "stereo" : "mono", - (val & 0x0080) ? ", nicam 2nd mono" : "", - (val & 0x0100) ? ", bilingual/SAP" : ""); - rxsubchans = V4L2_TUNER_SUB_MONO; - if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO; - if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1; - break; } if (rxsubchans != state->rxsubchans) { update = 1; - v4l_dbg(1, msp_debug, client, "watch: rxsubchans %d => %d\n", - state->rxsubchans,rxsubchans); + v4l_dbg(1, msp_debug, client, "watch: rxsubchans %02x => %02x\n", + state->rxsubchans, rxsubchans); state->rxsubchans = rxsubchans; } if (newnicam != state->nicam_on) { update = 1; v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n", - state->nicam_on,newnicam); + state->nicam_on, newnicam); state->nicam_on = newnicam; } return update; @@ -443,13 +427,8 @@ static void watch_stereo(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); - if (autodetect_stereo(client)) { - if (state->rxsubchans & V4L2_TUNER_SUB_STEREO) - msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO); - else if (state->rxsubchans & V4L2_TUNER_SUB_LANG1) - msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1); - else - msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); + if (msp3400c_detect_stereo(client)) { + msp3400c_set_audmode(client); } if (msp_once) @@ -461,7 +440,7 @@ int msp3400c_thread(void *data) struct i2c_client *client = data; struct msp_state *state = i2c_get_clientdata(client); struct msp3400c_carrier_detect *cd; - int count, max1,max2,val1,val2, val,this; + int count, max1, max2, val1, val2, val, this; v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); @@ -471,7 +450,7 @@ int msp3400c_thread(void *data) v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n"); restart: - v4l_dbg(1, msp_debug, client, "thread: restart scan\n"); + v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) break; @@ -485,13 +464,14 @@ int msp3400c_thread(void *data) /* mute */ msp_set_mute(client); - msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); + msp3400c_set_mode(client, MSP_MODE_AM_DETECT /* +1 */ ); val1 = val2 = 0; max1 = max2 = -1; state->watch_stereo = 0; + state->nicam_on = 0; /* some time for the tuner to sync */ - if (msp_sleep(state,200)) + if (msp_sleep(state, 200)) goto restart; /* carrier detect pass #1 -- main carrier */ @@ -506,7 +486,7 @@ int msp3400c_thread(void *data) } for (this = 0; this < count; this++) { - msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); + msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo); if (msp_sleep(state,100)) goto restart; val = msp_read_dsp(client, 0x1b); @@ -542,7 +522,7 @@ int msp3400c_thread(void *data) max2 = 0; } for (this = 0; this < count; this++) { - msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); + msp3400c_set_carrier(client, cd[this].cdo, cd[this].cdo); if (msp_sleep(state,100)) goto restart; val = msp_read_dsp(client, 0x1b); @@ -554,22 +534,20 @@ int msp3400c_thread(void *data) } /* program the msp3400 according to the results */ - state->main = msp3400c_carrier_detect_main[max1].cdo; + state->main = msp3400c_carrier_detect_main[max1].cdo; switch (max1) { case 1: /* 5.5 */ if (max2 == 0) { /* B/G FM-stereo */ state->second = msp3400c_carrier_detect_55[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - state->nicam_on = 0; - msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); + msp3400c_set_mode(client, MSP_MODE_FM_TERRA); state->watch_stereo = 1; } else if (max2 == 1 && state->has_nicam) { /* B/G NICAM */ state->second = msp3400c_carrier_detect_55[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_NICAM1); + msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); + msp3400c_set_carrier(client, state->second, state->main); state->nicam_on = 1; - msp3400c_setcarrier(client, state->second, state->main); state->watch_stereo = 1; } else { goto no_second; @@ -578,35 +556,31 @@ int msp3400c_thread(void *data) case 2: /* 6.0 */ /* PAL I NICAM */ state->second = MSP_CARRIER(6.552); - msp3400c_setmode(client, MSP_MODE_FM_NICAM2); + msp3400c_set_mode(client, MSP_MODE_FM_NICAM2); + msp3400c_set_carrier(client, state->second, state->main); state->nicam_on = 1; - msp3400c_setcarrier(client, state->second, state->main); state->watch_stereo = 1; break; case 3: /* 6.5 */ if (max2 == 1 || max2 == 2) { /* D/K FM-stereo */ state->second = msp3400c_carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - state->nicam_on = 0; - msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); + msp3400c_set_mode(client, MSP_MODE_FM_TERRA); state->watch_stereo = 1; } else if (max2 == 0 && (state->v4l2_std & V4L2_STD_SECAM)) { /* L NICAM or AM-mono */ state->second = msp3400c_carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_AM_NICAM); - state->nicam_on = 0; - msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); - msp3400c_setcarrier(client, state->second, state->main); + msp3400c_set_mode(client, MSP_MODE_AM_NICAM); + msp3400c_set_carrier(client, state->second, state->main); /* volume prescale for SCART (AM mono input) */ msp_write_dsp(client, 0x000d, 0x1900); state->watch_stereo = 1; } else if (max2 == 0 && state->has_nicam) { /* D/K NICAM */ state->second = msp3400c_carrier_detect_65[max2].cdo; - msp3400c_setmode(client, MSP_MODE_FM_NICAM1); + msp3400c_set_mode(client, MSP_MODE_FM_NICAM1); + msp3400c_set_carrier(client, state->second, state->main); state->nicam_on = 1; - msp3400c_setcarrier(client, state->second, state->main); state->watch_stereo = 1; } else { goto no_second; @@ -616,23 +590,25 @@ int msp3400c_thread(void *data) default: no_second: state->second = msp3400c_carrier_detect_main[max1].cdo; - msp3400c_setmode(client, MSP_MODE_FM_TERRA); - state->nicam_on = 0; - msp3400c_setcarrier(client, state->second, state->main); + msp3400c_set_mode(client, MSP_MODE_FM_TERRA); + msp3400c_set_carrier(client, state->second, state->main); state->rxsubchans = V4L2_TUNER_SUB_MONO; - msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); break; } /* unmute */ msp_set_audio(client); + msp3400c_set_audmode(client); if (msp_debug) msp3400c_print_mode(client); - /* monitor tv audio mode */ + /* monitor tv audio mode, the first time don't wait + so long to get a quick stereo/bilingual result */ + if (msp_sleep(state, 1000)) + goto restart; while (state->watch_stereo) { - if (msp_sleep(state,5000)) + if (msp_sleep(state, 5000)) goto restart; watch_stereo(client); } @@ -656,7 +632,7 @@ int msp3410d_thread(void *data) v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n"); restart: - v4l_dbg(1, msp_debug, client, "thread: restart scan\n"); + v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) break; @@ -681,9 +657,10 @@ int msp3410d_thread(void *data) else std = (state->v4l2_std & V4L2_STD_NTSC) ? 0x20 : 1; state->watch_stereo = 0; + state->nicam_on = 0; if (msp_debug) - v4l_dbg(1, msp_debug, client, "setting standard: %s (0x%04x)\n", + v4l_dbg(2, msp_debug, client, "setting standard: %s (0x%04x)\n", msp_standard_std_name(std), std); if (std != 1) { @@ -700,7 +677,7 @@ int msp3410d_thread(void *data) val = msp_read_dem(client, 0x7e); if (val < 0x07ff) break; - v4l_dbg(1, msp_debug, client, "detection still in progress\n"); + v4l_dbg(2, msp_debug, client, "detection still in progress\n"); } } for (i = 0; msp_stdlist[i].name != NULL; i++) @@ -739,48 +716,34 @@ int msp3410d_thread(void *data) state->rxsubchans = V4L2_TUNER_SUB_STEREO; state->nicam_on = 1; state->watch_stereo = 1; - msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO); break; case 0x0009: state->mode = MSP_MODE_AM_NICAM; state->rxsubchans = V4L2_TUNER_SUB_MONO; state->nicam_on = 1; - msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO); state->watch_stereo = 1; break; case 0x0020: /* BTSC */ - /* just turn on stereo */ + /* The pre-'G' models only have BTSC-mono */ state->mode = MSP_MODE_BTSC; - state->rxsubchans = V4L2_TUNER_SUB_STEREO; - state->nicam_on = 0; - state->watch_stereo = 1; - msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO); + state->rxsubchans = V4L2_TUNER_SUB_MONO; break; case 0x0040: /* FM radio */ state->mode = MSP_MODE_FM_RADIO; state->rxsubchans = V4L2_TUNER_SUB_STEREO; - state->audmode = V4L2_TUNER_MODE_STEREO; - state->nicam_on = 0; - state->watch_stereo = 0; /* not needed in theory if we have radio, but short programming enables carrier mute */ - msp3400c_setmode(client, MSP_MODE_FM_RADIO); - msp3400c_setcarrier(client, MSP_CARRIER(10.7), + msp3400c_set_mode(client, MSP_MODE_FM_RADIO); + msp3400c_set_carrier(client, MSP_CARRIER(10.7), MSP_CARRIER(10.7)); - /* scart routing */ + /* scart routing (this doesn't belong here I think) */ msp_set_scart(client,SCART_IN2,0); - /* msp34xx does radio decoding */ - msp_write_dsp(client, 0x08, 0x0020); - msp_write_dsp(client, 0x09, 0x0020); - msp_write_dsp(client, 0x0b, 0x0020); break; case 0x0003: case 0x0004: case 0x0005: state->mode = MSP_MODE_FM_TERRA; state->rxsubchans = V4L2_TUNER_SUB_MONO; - state->audmode = V4L2_TUNER_MODE_MONO; - state->nicam_on = 0; state->watch_stereo = 1; break; } @@ -791,11 +754,16 @@ int msp3410d_thread(void *data) if (state->has_i2s_conf) msp_write_dem(client, 0x40, state->i2s_mode); - /* monitor tv audio mode */ + msp3400c_set_audmode(client); + + /* monitor tv audio mode, the first time don't wait + so long to get a quick stereo/bilingual result */ + if (msp_sleep(state, 1000)) + goto restart; while (state->watch_stereo) { - if (msp_sleep(state,5000)) - goto restart; watch_stereo(client); + if (msp_sleep(state, 5000)) + goto restart; } } v4l_dbg(1, msp_debug, client, "thread: exit\n"); @@ -813,7 +781,7 @@ int msp3410d_thread(void *data) * the value for source is the same as bit 15:8 of DSP registers 0x08, * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B * - * this function replaces msp3400c_setstereo + * this function replaces msp3400c_set_audmode */ static void msp34xxg_set_source(struct i2c_client *client, int source) { @@ -826,12 +794,7 @@ static void msp34xxg_set_source(struct i2c_client *client, int source) int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20); v4l_dbg(1, msp_debug, client, "set source to %d (0x%x)\n", source, value); - /* Loudspeaker Output */ - msp_write_dsp(client, 0x08, value); - /* SCART1 DA Output */ - msp_write_dsp(client, 0x0a, value); - /* Quasi-peak detector */ - msp_write_dsp(client, 0x0c, value); + msp_set_source(client, value); /* * set identification threshold. Personally, I * I set it to a higher value that the default @@ -948,13 +911,14 @@ int msp34xxg_thread(void *data) if (msp_write_dsp(client, 0x13, state->acb)) return -1; - msp_write_dem(client, 0x40, state->i2s_mode); + if (state->has_i2s_conf) + msp_write_dem(client, 0x40, state->i2s_mode); } v4l_dbg(1, msp_debug, client, "thread: exit\n"); return 0; } -void msp34xxg_detect_stereo(struct i2c_client *client) +static void msp34xxg_detect_stereo(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); @@ -964,11 +928,11 @@ void msp34xxg_detect_stereo(struct i2c_client *client) state->rxsubchans = 0; if (is_stereo) - state->rxsubchans |= V4L2_TUNER_SUB_STEREO; + state->rxsubchans = V4L2_TUNER_SUB_STEREO; else - state->rxsubchans |= V4L2_TUNER_SUB_MONO; + state->rxsubchans = V4L2_TUNER_SUB_MONO; if (is_bilingual) { - state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; /* I'm supposed to check whether it's SAP or not * and set only LANG2/SAP in this case. Yet, the MSP * does a lot of work to hide this and handle everything @@ -980,12 +944,12 @@ void msp34xxg_detect_stereo(struct i2c_client *client) status, is_stereo, is_bilingual, state->rxsubchans); } -void msp34xxg_set_audmode(struct i2c_client *client, int audmode) +static void msp34xxg_set_audmode(struct i2c_client *client) { struct msp_state *state = i2c_get_clientdata(client); int source; - switch (audmode) { + switch (state->audmode) { case V4L2_TUNER_MODE_MONO: source = 0; /* mono only */ break; @@ -1000,11 +964,40 @@ void msp34xxg_set_audmode(struct i2c_client *client, int audmode) source = 4; /* stereo or B */ break; default: - audmode = 0; source = 1; break; } - state->audmode = audmode; msp34xxg_set_source(client, source); } +void msp_set_audmode(struct i2c_client *client) +{ + struct msp_state *state = i2c_get_clientdata(client); + + switch (state->opmode) { + case OPMODE_MANUAL: + case OPMODE_AUTODETECT: + state->watch_stereo = 0; + msp3400c_set_audmode(client); + break; + case OPMODE_AUTOSELECT: + msp34xxg_set_audmode(client); + break; + } +} + +void msp_detect_stereo(struct i2c_client *client) +{ + struct msp_state *state = i2c_get_clientdata(client); + + switch (state->opmode) { + case OPMODE_MANUAL: + case OPMODE_AUTODETECT: + msp3400c_detect_stereo(client); + break; + case OPMODE_AUTOSELECT: + msp34xxg_detect_stereo(client); + break; + } +} + diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h index a9ac57d0700..6fb5c8c994e 100644 --- a/drivers/media/video/msp3400.h +++ b/drivers/media/video/msp3400.h @@ -104,14 +104,12 @@ int msp_sleep(struct msp_state *state, int timeout); /* msp3400-kthreads.c */ const char *msp_standard_std_name(int std); -void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2); -void msp3400c_setmode(struct i2c_client *client, int type); -void msp3400c_setstereo(struct i2c_client *client, int mode); -int autodetect_stereo(struct i2c_client *client); +void msp_set_audmode(struct i2c_client *client); +void msp_detect_stereo(struct i2c_client *client); int msp3400c_thread(void *data); int msp3410d_thread(void *data); int msp34xxg_thread(void *data); -void msp34xxg_detect_stereo(struct i2c_client *client); -void msp34xxg_set_audmode(struct i2c_client *client, int audmode); +void msp3400c_set_mode(struct i2c_client *client, int mode); +void msp3400c_set_carrier(struct i2c_client *client, int cdo1, int cdo2); #endif /* MSP3400_H */ diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c index 41715cacf92..eb3b3186749 100644 --- a/drivers/media/video/mxb.c +++ b/drivers/media/video/mxb.c @@ -1,11 +1,11 @@ /* mxb - v4l2 driver for the Multimedia eXtension Board - + Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de> Visit http://www.mihu.de/linux/saa7146/mxb/ for further details about this card. - + 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 @@ -35,12 +35,12 @@ #define I2C_SAA7111 0x24 -#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0) +#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0) /* global variable */ static int mxb_num = 0; -/* initial frequence the tuner will be tuned to. +/* initial frequence the tuner will be tuned to. in verden (lower saxony, germany) 4148 is a channel called "phoenix" */ static int freq = 4148; @@ -55,7 +55,7 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); enum { TUNER, AUX1, AUX3, AUX3_YC }; static struct v4l2_input mxb_inputs[MXB_INPUTS] = { - { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, + { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, @@ -66,7 +66,7 @@ static struct v4l2_input mxb_inputs[MXB_INPUTS] = { static struct { int hps_source; int hps_sync; -} input_port_selection[MXB_INPUTS] = { +} input_port_selection[MXB_INPUTS] = { { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, { SAA7146_HPS_SOURCE_PORT_A, SAA7146_HPS_SYNC_PORT_A }, @@ -81,7 +81,7 @@ static int video_audio_connect[MXB_INPUTS] = /* these are the necessary input-output-pins for bringing one audio source (see above) to the CD-output */ static struct tea6420_multiplex TEA6420_cd[MXB_AUDIOS+1][2] = - { + { {{1,1,0},{1,1,0}}, /* Tuner */ {{5,1,0},{6,1,0}}, /* AUX 1 */ {{4,1,0},{6,1,0}}, /* AUX 2 */ @@ -122,8 +122,8 @@ static struct saa7146_extension_ioctls ioctls[] = { { VIDIOC_S_FREQUENCY, SAA7146_EXCLUSIVE }, { VIDIOC_G_AUDIO, SAA7146_EXCLUSIVE }, { VIDIOC_S_AUDIO, SAA7146_EXCLUSIVE }, - { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */ - { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */ + { MXB_S_AUDIO_CD, SAA7146_EXCLUSIVE }, /* custom control */ + { MXB_S_AUDIO_LINE, SAA7146_EXCLUSIVE }, /* custom control */ { 0, 0 } }; @@ -132,7 +132,7 @@ struct mxb struct video_device *video_dev; struct video_device *vbi_dev; - struct i2c_adapter i2c_adapter; + struct i2c_adapter i2c_adapter; struct i2c_client* saa7111a; struct i2c_client* tda9840; @@ -200,15 +200,15 @@ static int mxb_probe(struct saa7146_dev* dev) client = list_entry(item, struct i2c_client, list); if( I2C_TEA6420_1 == client->addr ) mxb->tea6420_1 = client; - if( I2C_TEA6420_2 == client->addr ) + if( I2C_TEA6420_2 == client->addr ) mxb->tea6420_2 = client; - if( I2C_TEA6415C_2 == client->addr ) + if( I2C_TEA6415C_2 == client->addr ) mxb->tea6415c = client; - if( I2C_TDA9840 == client->addr ) + if( I2C_TDA9840 == client->addr ) mxb->tda9840 = client; if( I2C_SAA7111 == client->addr ) mxb->saa7111a = client; - if( 0x60 == client->addr ) + if( 0x60 == client->addr ) mxb->tuner = client; } @@ -222,7 +222,7 @@ static int mxb_probe(struct saa7146_dev* dev) return -ENODEV; } - /* all devices are present, probe was successful */ + /* all devices are present, probe was successful */ /* we store the pointer in our private data field */ dev->ext_priv = mxb; @@ -230,7 +230,7 @@ static int mxb_probe(struct saa7146_dev* dev) return 0; } -/* some init data for the saa7740, the so-called 'sound arena module'. +/* some init data for the saa7740, the so-called 'sound arena module'. there are no specs available, so we simply use some init values */ static struct { int length; @@ -330,7 +330,7 @@ static int mxb_init_done(struct saa7146_dev* dev) v4l2_std_id std = V4L2_STD_PAL_BG; int i = 0, err = 0; - struct tea6415c_multiplex vm; + struct tea6415c_multiplex vm; /* select video mode in saa7111a */ i = VIDEO_MODE_PAL; @@ -380,16 +380,16 @@ static int mxb_init_done(struct saa7146_dev* dev) vm.in = 3; vm.out = 13; mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm); - + /* the rest for mxb */ mxb->cur_input = 0; mxb->cur_mute = 1; mxb->cur_mode = V4L2_TUNER_MODE_STEREO; mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &mxb->cur_mode); - + /* check if the saa7740 (aka 'sound arena module') is present - on the mxb. if so, we must initialize it. due to lack of + on the mxb. if so, we must initialize it. due to lack of informations about the saa7740, the values were reverse engineered. */ msg.addr = 0x1b; @@ -409,7 +409,7 @@ static int mxb_init_done(struct saa7146_dev* dev) break; } - msg.len = mxb_saa7740_init[i].length; + msg.len = mxb_saa7740_init[i].length; msg.buf = &mxb_saa7740_init[i].data[0]; if( 1 != (err = i2c_transfer(&mxb->i2c_adapter, &msg, 1))) { DEB_D(("failed to initialize 'sound arena module'.\n")); @@ -418,12 +418,12 @@ static int mxb_init_done(struct saa7146_dev* dev) } INFO(("'sound arena module' detected.\n")); } -err: +err: /* the rest for saa7146: you should definitely set some basic values for the input-port handling of the saa7146. */ /* ext->saa has been filled by the core driver */ - + /* some stuff is done via variables */ saa7146_set_hps_source_and_sync(dev, input_port_selection[mxb->cur_input].hps_source, input_port_selection[mxb->cur_input].hps_sync); @@ -431,7 +431,7 @@ err: /* this is ugly, but because of the fact that this is completely hardware dependend, it should be done directly... */ - saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, DD1_STREAM_B, 0x00000000); saa7146_write(dev, DD1_INIT, 0x02000200); saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); @@ -453,7 +453,7 @@ static struct saa7146_ext_vv vv_data; static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) { struct mxb* mxb = (struct mxb*)dev->ext_priv; - + DEB_EE(("dev:%p\n",dev)); /* checking for i2c-devices can be omitted here, because we @@ -464,7 +464,7 @@ static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data ERR(("cannot register capture v4l2 device. skipping.\n")); return -1; } - + /* initialization stuff (vbi) (only for revision > 0 and for extensions which want it)*/ if( 0 != MXB_BOARD_CAN_DO_VBI(dev)) { if( 0 != saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { @@ -513,17 +513,17 @@ static int mxb_detach(struct saa7146_dev* dev) return 0; } -static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) +static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) { struct saa7146_dev *dev = fh->dev; struct mxb* mxb = (struct mxb*)dev->ext_priv; - struct saa7146_vv *vv = dev->vv_data; - + struct saa7146_vv *vv = dev->vv_data; + switch(cmd) { case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; - + DEB_EE(("VIDIOC_ENUMINPUT %d.\n",i->index)); if( i->index < 0 || i->index >= MXB_INPUTS) { return -EINVAL; @@ -559,11 +559,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) break; } } - + if( i < 0 ) { return -EAGAIN; } - + switch (vc->id ) { case V4L2_CID_AUDIO_MUTE: { vc->value = mxb->cur_mute; @@ -571,7 +571,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) return 0; } } - + DEB_EE(("VIDIOC_G_CTRL V4L2_CID_AUDIO_MUTE:%d.\n",vc->value)); return 0; } @@ -580,17 +580,17 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) { struct v4l2_control *vc = arg; int i = 0; - + for (i = MAXCONTROLS - 1; i >= 0; i--) { if (mxb_controls[i].id == vc->id) { break; } } - + if( i < 0 ) { return -EAGAIN; } - + switch (vc->id ) { case V4L2_CID_AUDIO_MUTE: { mxb->cur_mute = vc->value; @@ -614,12 +614,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) *input = mxb->cur_input; DEB_EE(("VIDIOC_G_INPUT %d.\n",*input)); - return 0; - } + return 0; + } case VIDIOC_S_INPUT: { int input = *(int *)arg; - struct tea6415c_multiplex vm; + struct tea6415c_multiplex vm; int i = 0; DEB_EE(("VIDIOC_S_INPUT %d.\n",input)); @@ -627,34 +627,34 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) if (input < 0 || input >= MXB_INPUTS) { return -EINVAL; } - + /* fixme: locke das setzen des inputs mit hilfe des mutexes - down(&dev->lock); + mutex_lock(&dev->lock); video_mux(dev,*i); - up(&dev->lock); + mutex_unlock(&dev->lock); */ - + /* fixme: check if streaming capture if ( 0 != dev->streaming ) { DEB_D(("VIDIOC_S_INPUT illegal while streaming.\n")); return -EPERM; } */ - + mxb->cur_input = input; - + saa7146_set_hps_source_and_sync(dev, input_port_selection[input].hps_source, input_port_selection[input].hps_sync); - + /* prepare switching of tea6415c and saa7111a; have a look at the 'background'-file for further informations */ switch( input ) { - + case TUNER: { i = 0; vm.in = 3; vm.out = 17; - + if ( 0 != mxb->tea6415c->driver->command(mxb->tea6415c,TEA6415C_SWITCH, &vm)) { printk("VIDIOC_S_INPUT: could not address tea6415c #1\n"); return -EFAULT; @@ -662,7 +662,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) /* connect tuner-output always to multicable */ vm.in = 3; vm.out = 13; - break; + break; } case AUX3_YC: { @@ -703,11 +703,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) break; } } - + /* switch video in saa7111a */ if ( 0 != mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_INPUT, &i)) { printk("VIDIOC_S_INPUT: could not address saa7111a #1.\n"); - } + } /* switch the audio-source only if necessary */ if( 0 == mxb->cur_mute ) { @@ -738,11 +738,11 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) t->rangehigh = 13684; /* 855.25 MHz / 62.5 kHz = 13684 */ /* FIXME: add the real signal strength here */ t->signal = 0xffff; - t->afc = 0; + t->afc = 0; mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte); t->audmode = mxb->cur_mode; - + if( byte < 0 ) { t->rxsubchans = V4L2_TUNER_SUB_MONO; } else { @@ -777,12 +777,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) struct v4l2_tuner *t = arg; int result = 0; int byte = 0; - + if( 0 != t->index ) { DEB_D(("VIDIOC_S_TUNER: channel %d does not have a tuner attached.\n",t->index)); return -EINVAL; } - + switch(t->audmode) { case V4L2_TUNER_MODE_STEREO: { mxb->cur_mode = V4L2_TUNER_MODE_STEREO; @@ -813,7 +813,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) if( 0 != (result = mxb->tda9840->driver->command(mxb->tda9840, TDA9840_SWITCH, &byte))) { printk("VIDIOC_S_TUNER error. result:%d, byte:%d\n",result,byte); } - + return 0; } case VIDIOC_G_FREQUENCY: @@ -839,7 +839,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) if (V4L2_TUNER_ANALOG_TV != f->type) return -EINVAL; - + if(0 != mxb->cur_input) { DEB_D(("VIDIOC_S_FREQ: channel %d does not have a tuner!\n",mxb->cur_input)); return -EINVAL; @@ -848,7 +848,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) mxb->cur_freq = *f; DEB_EE(("VIDIOC_S_FREQUENCY: freq:0x%08x.\n", mxb->cur_freq.frequency)); - /* tune in desired frequency */ + /* tune in desired frequency */ mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_FREQUENCY, &mxb->cur_freq); /* hack: changing the frequency should invalidate the vbi-counter (=> alevt) */ @@ -861,12 +861,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) case MXB_S_AUDIO_CD: { int i = *(int*)arg; - + if( i < 0 || i >= MXB_AUDIOS ) { DEB_D(("illegal argument to MXB_S_AUDIO_CD: i:%d.\n",i)); return -EINVAL; } - + DEB_EE(("MXB_S_AUDIO_CD: i:%d.\n",i)); mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_cd[i][0]); @@ -877,12 +877,12 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) case MXB_S_AUDIO_LINE: { int i = *(int*)arg; - + if( i < 0 || i >= MXB_AUDIOS ) { DEB_D(("illegal argument to MXB_S_AUDIO_LINE: i:%d.\n",i)); return -EINVAL; } - + DEB_EE(("MXB_S_AUDIO_LINE: i:%d.\n",i)); mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[i][0]); mxb->tea6420_2->driver->command(mxb->tea6420_2,TEA6420_SWITCH, &TEA6420_line[i][1]); @@ -894,13 +894,13 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) struct v4l2_audio *a = arg; if( a->index < 0 || a->index > MXB_INPUTS ) { - DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index)); + DEB_D(("VIDIOC_G_AUDIO %d out of range.\n",a->index)); return -EINVAL; } - - DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index)); + + DEB_EE(("VIDIOC_G_AUDIO %d.\n",a->index)); memcpy(a, &mxb_audios[video_audio_connect[mxb->cur_input]], sizeof(struct v4l2_audio)); - + return 0; } case VIDIOC_S_AUDIO: @@ -908,7 +908,7 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) struct v4l2_audio *a = arg; DEB_D(("VIDIOC_S_AUDIO %d.\n",a->index)); return 0; - } + } default: /* DEB2(printk("does not handle this ioctl.\n")); @@ -928,7 +928,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) v4l2_std_id std = V4L2_STD_PAL_I; DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n")); /* set the 7146 gpio register -- I don't know what this does exactly */ - saa7146_write(dev, GPIO_CTRL, 0x00404050); + saa7146_write(dev, GPIO_CTRL, 0x00404050); /* unset the 7111 gpio register -- I don't know what this does exactly */ mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero); mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std); @@ -936,7 +936,7 @@ static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) v4l2_std_id std = V4L2_STD_PAL_BG; DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n")); /* set the 7146 gpio register -- I don't know what this does exactly */ - saa7146_write(dev, GPIO_CTRL, 0x00404050); + saa7146_write(dev, GPIO_CTRL, 0x00404050); /* set the 7111 gpio register -- I don't know what this does exactly */ mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one); mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std); @@ -969,8 +969,8 @@ static struct saa7146_standard standard[] = { }; static struct saa7146_pci_extension_data mxb = { - .ext_priv = "Multimedia eXtension Board", - .ext = &extension, + .ext_priv = "Multimedia eXtension Board", + .ext = &extension, }; static struct pci_device_id pci_tbl[] = { @@ -992,7 +992,7 @@ static struct saa7146_ext_vv vv_data = { .capabilities = V4L2_CAP_TUNER | V4L2_CAP_VBI_CAPTURE, .stds = &standard[0], .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), - .std_callback = &std_callback, + .std_callback = &std_callback, .ioctls = &ioctls[0], .ioctl = mxb_ioctl, }; @@ -1000,7 +1000,7 @@ static struct saa7146_ext_vv vv_data = { static struct saa7146_extension extension = { .name = MXB_IDENTIFIER, .flags = SAA7146_USE_I2C_IRQ, - + .pci_tbl = &pci_tbl[0], .module = THIS_MODULE, @@ -1010,7 +1010,7 @@ static struct saa7146_extension extension = { .irq_mask = 0, .irq_func = NULL, -}; +}; static int __init mxb_init_module(void) { @@ -1018,7 +1018,7 @@ static int __init mxb_init_module(void) DEB_S(("failed to register extension.\n")); return -ENODEV; } - + return 0; } diff --git a/drivers/media/video/mxb.h b/drivers/media/video/mxb.h index 2332ed5f7c6..400a57ba62e 100644 --- a/drivers/media/video/mxb.h +++ b/drivers/media/video/mxb.h @@ -38,5 +38,5 @@ static struct v4l2_audio mxb_audios[MXB_AUDIOS] = { .name = "CD-ROM (X10)", .capability = V4L2_AUDCAP_STEREO, } -}; +}; #endif diff --git a/drivers/media/video/planb.c b/drivers/media/video/planb.c index f3fc361bec9..15fd85acabd 100644 --- a/drivers/media/video/planb.c +++ b/drivers/media/video/planb.c @@ -48,7 +48,7 @@ #include <asm/pgtable.h> #include <asm/page.h> #include <asm/irq.h> -#include <asm/semaphore.h> +#include <linux/mutex.h> #include "planb.h" #include "saa7196.h" @@ -329,12 +329,12 @@ static volatile struct dbdma_cmd *cmd_geo_setup( static inline void planb_lock(struct planb *pb) { - down(&pb->lock); + mutex_lock(&pb->lock); } static inline void planb_unlock(struct planb *pb) { - up(&pb->lock); + mutex_unlock(&pb->lock); } /***************/ @@ -2067,7 +2067,7 @@ static int init_planb(struct planb *pb) #endif pb->tab_size = PLANB_MAXLINES + 40; pb->suspend = 0; - init_MUTEX(&pb->lock); + mutex_init(&pb->lock); pb->ch1_cmd = 0; pb->ch2_cmd = 0; pb->mask = 0; diff --git a/drivers/media/video/planb.h b/drivers/media/video/planb.h index 8a0faad1611..79b6b561426 100644 --- a/drivers/media/video/planb.h +++ b/drivers/media/video/planb.h @@ -174,7 +174,7 @@ struct planb { int user; unsigned int tab_size; int maxlines; - struct semaphore lock; + struct mutex lock; unsigned int irq; /* interrupt number */ volatile unsigned int intr_mask; diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c index 9e644863948..05ca55939e7 100644 --- a/drivers/media/video/pms.c +++ b/drivers/media/video/pms.c @@ -30,6 +30,8 @@ #include <asm/io.h> #include <linux/sched.h> #include <linux/videodev.h> +#include <linux/mutex.h> + #include <asm/uaccess.h> @@ -44,7 +46,7 @@ struct pms_device struct video_picture picture; int height; int width; - struct semaphore lock; + struct mutex lock; }; struct i2c_info @@ -724,10 +726,10 @@ static int pms_do_ioctl(struct inode *inode, struct file *file, struct video_channel *v = arg; if(v->channel<0 || v->channel>3) return -EINVAL; - down(&pd->lock); + mutex_lock(&pd->lock); pms_videosource(v->channel&1); pms_vcrinput(v->channel>>1); - up(&pd->lock); + mutex_unlock(&pd->lock); return 0; } case VIDIOCGTUNER: @@ -761,7 +763,7 @@ static int pms_do_ioctl(struct inode *inode, struct file *file, struct video_tuner *v = arg; if(v->tuner) return -EINVAL; - down(&pd->lock); + mutex_lock(&pd->lock); switch(v->mode) { case VIDEO_MODE_AUTO: @@ -785,10 +787,10 @@ static int pms_do_ioctl(struct inode *inode, struct file *file, pms_format(2); break; default: - up(&pd->lock); + mutex_unlock(&pd->lock); return -EINVAL; } - up(&pd->lock); + mutex_unlock(&pd->lock); return 0; } case VIDIOCGPICT: @@ -809,12 +811,12 @@ static int pms_do_ioctl(struct inode *inode, struct file *file, * Now load the card. */ - down(&pd->lock); + mutex_lock(&pd->lock); pms_brightness(p->brightness>>8); pms_hue(p->hue>>8); pms_colour(p->colour>>8); pms_contrast(p->contrast>>8); - up(&pd->lock); + mutex_unlock(&pd->lock); return 0; } case VIDIOCSWIN: @@ -830,9 +832,9 @@ static int pms_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; pd->width=vw->width; pd->height=vw->height; - down(&pd->lock); + mutex_lock(&pd->lock); pms_resolution(pd->width, pd->height); - up(&pd->lock); /* Ok we figured out what to use from our wide choice */ + mutex_unlock(&pd->lock); /* Ok we figured out what to use from our wide choice */ return 0; } case VIDIOCGWIN: @@ -872,9 +874,9 @@ static ssize_t pms_read(struct file *file, char __user *buf, struct pms_device *pd=(struct pms_device *)v; int len; - down(&pd->lock); + mutex_lock(&pd->lock); len=pms_capture(pd, buf, (pd->picture.depth==16)?0:1,count); - up(&pd->lock); + mutex_unlock(&pd->lock); return len; } @@ -1029,7 +1031,7 @@ static int __init init_pms_cards(void) return -ENODEV; } memcpy(&pms_device, &pms_template, sizeof(pms_template)); - init_MUTEX(&pms_device.lock); + mutex_init(&pms_device.lock); pms_device.height=240; pms_device.width=320; pms_swsense(75); diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c index 2ce01020130..dd830e0e5e9 100644 --- a/drivers/media/video/saa5246a.c +++ b/drivers/media/video/saa5246a.c @@ -46,6 +46,8 @@ #include <linux/i2c.h> #include <linux/videotext.h> #include <linux/videodev.h> +#include <linux/mutex.h> + #include "saa5246a.h" MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>"); @@ -57,7 +59,7 @@ struct saa5246a_device u8 pgbuf[NUM_DAUS][VTX_VIRTUALSIZE]; int is_searching[NUM_DAUS]; struct i2c_client *client; - struct semaphore lock; + struct mutex lock; }; static struct video_device saa_template; /* Declared near bottom */ @@ -90,7 +92,7 @@ static int saa5246a_attach(struct i2c_adapter *adap, int addr, int kind) return -ENOMEM; } strlcpy(client->name, IF_NAME, I2C_NAME_SIZE); - init_MUTEX(&t->lock); + mutex_init(&t->lock); /* * Now create a video4linux device @@ -719,9 +721,9 @@ static int saa5246a_ioctl(struct inode *inode, struct file *file, int err; cmd = vtx_fix_command(cmd); - down(&t->lock); + mutex_lock(&t->lock); err = video_usercopy(inode, file, cmd, arg, do_saa5246a_ioctl); - up(&t->lock); + mutex_unlock(&t->lock); return err; } diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c index 5694eb58c3a..a9f3cf0b1e3 100644 --- a/drivers/media/video/saa5249.c +++ b/drivers/media/video/saa5249.c @@ -56,6 +56,8 @@ #include <linux/i2c.h> #include <linux/videotext.h> #include <linux/videodev.h> +#include <linux/mutex.h> + #include <asm/io.h> #include <asm/uaccess.h> @@ -105,7 +107,7 @@ struct saa5249_device int disp_mode; int virtual_mode; struct i2c_client *client; - struct semaphore lock; + struct mutex lock; }; @@ -158,7 +160,7 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind) return -ENOMEM; } strlcpy(client->name, IF_NAME, I2C_NAME_SIZE); - init_MUTEX(&t->lock); + mutex_init(&t->lock); /* * Now create a video4linux device @@ -619,9 +621,9 @@ static int saa5249_ioctl(struct inode *inode, struct file *file, int err; cmd = vtx_fix_command(cmd); - down(&t->lock); + mutex_lock(&t->lock); err = video_usercopy(inode,file,cmd,arg,do_saa5249_ioctl); - up(&t->lock); + mutex_unlock(&t->lock); return err; } diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c index ffd87ce5555..b184fd00b4e 100644 --- a/drivers/media/video/saa7115.c +++ b/drivers/media/video/saa7115.c @@ -1,4 +1,4 @@ -/* saa7115 - Philips SAA7114/SAA7115 video decoder driver +/* saa7115 - Philips SAA7113/SAA7114/SAA7115 video decoder driver * * Based on saa7114 driver by Maxim Yevtyushkin, which is based on * the saa7111 driver by Dave Perks. @@ -16,6 +16,7 @@ * (2/17/2003) * * VBI support (2004) and cleanups (2005) by Hans Verkuil <hverkuil@xs4all.nl> + * SAA7113 support by Mauro Carvalho Chehab <mchehab@infradead.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -42,8 +43,9 @@ #include <media/audiochip.h> #include <asm/div64.h> -MODULE_DESCRIPTION("Philips SAA7114/SAA7115 video decoder driver"); -MODULE_AUTHOR("Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, Hans Verkuil"); +MODULE_DESCRIPTION("Philips SAA7113/SAA7114/SAA7115 video decoder driver"); +MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, " + "Hans Verkuil, Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); static int debug = 0; @@ -51,7 +53,10 @@ module_param(debug, bool, 0644); MODULE_PARM_DESC(debug, "Debug level (0-1)"); -static unsigned short normal_i2c[] = { 0x42 >> 1, 0x40 >> 1, I2C_CLIENT_END }; +static unsigned short normal_i2c[] = { + 0x4a >>1, 0x48 >>1, /* SAA7113 */ + 0x42 >> 1, 0x40 >> 1, /* SAA7114 and SAA7115 */ + I2C_CLIENT_END }; I2C_CLIENT_INSMOD; @@ -101,10 +106,12 @@ static inline int saa7115_read(struct i2c_client *client, u8 reg) Hauppauge driver sets. */ static const unsigned char saa7115_init_auto_input[] = { + /* Front-End Part */ 0x01, 0x48, /* white peak control disabled */ 0x03, 0x20, /* was 0x30. 0x20: long vertical blanking */ 0x04, 0x90, /* analog gain set to 0 */ 0x05, 0x90, /* analog gain set to 0 */ + /* Decoder Part */ 0x06, 0xeb, /* horiz sync begin = -21 */ 0x07, 0xe0, /* horiz sync stop = -17 */ 0x0a, 0x80, /* was 0x88. decoder brightness, 0x80 is itu standard */ @@ -123,6 +130,8 @@ static const unsigned char saa7115_init_auto_input[] = { 0x1b, 0x42, /* misc chroma control 0x42 = recommended */ 0x1c, 0xa9, /* combfilter control 0xA9 = recommended */ 0x1d, 0x01, /* combfilter control 0x01 = recommended */ + + /* Power Device Control */ 0x88, 0xd0, /* reset device */ 0x88, 0xf0, /* set device programmed, all in operational mode */ 0x00, 0x00 @@ -338,6 +347,33 @@ static const unsigned char saa7115_cfg_vbi_off[] = { 0x00, 0x00 }; +static const unsigned char saa7113_init_auto_input[] = { + 0x01, 0x08, /* PH7113_INCREMENT_DELAY - (1) (1) (1) (1) IDEL3 IDEL2 IDELL1 IDEL0 */ + 0x02, 0xc2, /* PH7113_ANALOG_INPUT_CONTR_1 - FUSE1 FUSE0 GUDL1 GUDL0 MODE3 MODE2 MODE1 MODE0 */ + 0x03, 0x30, /* PH7113_ANALOG_INPUT_CONTR_2 - (1) HLNRS VBSL WPOFF HOLDG GAFIX GAI28 GAI18 */ + 0x04, 0x00, /* PH7113_ANALOG_INPUT_CONTR_3 - GAI17 GAI16 GAI15 GAI14 GAI13 GAI12 GAI11 GAI10 */ + 0x05, 0x00, /* PH7113_ANALOG_INPUT_CONTR_4 - GAI27 GAI26 GAI25 GAI24 GAI23 GAI22 GAI21 GAI20 */ + 0x06, 0x89, /* PH7113_HORIZONTAL_SYNC_START - HSB7 HSB6 HSB5 HSB4 HSB3 HSB2 HSB1 HSB0 */ + 0x07, 0x0d, /* PH7113_HORIZONTAL_SYNC_STOP - HSS7 HSS6 HSS5 HSS4 HSS3 HSS2 HSS1 HSS0 */ + 0x08, 0x88, /* PH7113_SYNC_CONTROL - AUFD FSEL FOET HTC1 HTC0 HPLL VNOI1 VNOI0 */ + 0x09, 0x01, /* PH7113_LUMINANCE_CONTROL - BYPS PREF BPSS1 BPSS0 VBLB UPTCV APER1 APER0 */ + 0x0a, 0x80, /* PH7113_LUMINANCE_BRIGHTNESS - BRIG7 BRIG6 BRIG5 BRIG4 BRIG3 BRIG2 BRIG1 BRIG0 */ + 0x0b, 0x47, /* PH7113_LUMINANCE_CONTRAST - CONT7 CONT6 CONT5 CONT4 CONT3 CONT2 CONT1 CONT0 */ + 0x0c, 0x40, /* PH7113_CHROMA_SATURATION - SATN7 SATN6 SATN5 SATN4 SATN3 SATN2 SATN1 SATN0 */ + 0x0d, 0x00, /* PH7113_CHROMA_HUE_CONTROL - HUEC7 HUEC6 HUEC5 HUEC4 HUEC3 HUEC2 HUEC1 HUEC0 */ + 0x0e, 0x01, /* PH7113_CHROMA_CONTROL - CDTO CSTD2 CSTD1 CSTD0 DCCF FCTC CHBW1 CHBW0 */ + 0x0f, 0x2a, /* PH7113_CHROMA_GAIN_CONTROL - ACGC CGAIN6 CGAIN5 CGAIN4 CGAIN3 CGAIN2 CGAIN1 CGAIN0 */ + 0x10, 0x08, /* PH7113_FORMAT_DELAY_CONTROL - OFTS1 OFTS0 HDEL1 HDEL0 VRLN YDEL2 YDEL1 YDEL0 */ + 0x11, 0x0c, /* PH7113_OUTPUT_CONTROL_1 - GPSW1 CM99 GPSW0 HLSEL OEYC OERT VIPB COLO */ + 0x12, 0x07, /* PH7113_OUTPUT_CONTROL_2 - RTSE13 RTSE12 RTSE11 RTSE10 RTSE03 RTSE02 RTSE01 RTSE00 */ + 0x13, 0x00, /* PH7113_OUTPUT_CONTROL_3 - ADLSB (1) (1) OLDSB FIDP (1) AOSL1 AOSL0 */ + 0x14, 0x00, /* RESERVED 14 - (1) (1) (1) (1) (1) (1) (1) (1) */ + 0x15, 0x00, /* PH7113_V_GATE1_START - VSTA7 VSTA6 VSTA5 VSTA4 VSTA3 VSTA2 VSTA1 VSTA0 */ + 0x16, 0x00, /* PH7113_V_GATE1_STOP - VSTO7 VSTO6 VSTO5 VSTO4 VSTO3 VSTO2 VSTO1 VSTO0 */ + 0x17, 0x00, /* PH7113_V_GATE1_MSB - (1) (1) (1) (1) (1) (1) VSTO8 VSTA8 */ + 0x00, 0x00 +}; + static const unsigned char saa7115_init_misc[] = { 0x38, 0x03, /* audio stuff */ 0x39, 0x10, @@ -677,10 +713,35 @@ static void saa7115_set_v4lstd(struct i2c_client *client, v4l2_std_id std) saa7115_writeregs(client, saa7115_cfg_50hz_video); } + /* Register 0E - Bits D6-D4 on NO-AUTO mode + (SAA7113 doesn't have auto mode) + 50 Hz / 625 lines 60 Hz / 525 lines + 000 PAL BGDHI (4.43Mhz) NTSC M (3.58MHz) + 001 NTSC 4.43 (50 Hz) PAL 4.43 (60 Hz) + 010 Combination-PAL N (3.58MHz) NTSC 4.43 (60 Hz) + 011 NTSC N (3.58MHz) PAL M (3.58MHz) + 100 reserved NTSC-Japan (3.58MHz) + */ + if (state->ident == V4L2_IDENT_SAA7113) { + u8 reg = saa7115_read(client, 0x0e) & 0x8f; + + if (std == V4L2_STD_PAL_M) { + reg|=0x30; + } else if (std == V4L2_STD_PAL_N) { + reg|=0x20; + } else if (std == V4L2_STD_PAL_60) { + reg|=0x10; + } else if (std == V4L2_STD_NTSC_M_JP) { + reg|=0x40; + } + saa7115_write(client, 0x0e, reg); + } + + state->std = std; /* restart task B if needed */ - if (taskb && state->ident == V4L2_IDENT_SAA7114) { + if (taskb && state->ident != V4L2_IDENT_SAA7115) { saa7115_writeregs(client, saa7115_cfg_vbi_on); } @@ -703,7 +764,7 @@ static void saa7115_log_status(struct i2c_client *client) int vcr; v4l_info(client, "Audio frequency: %d Hz\n", state->audclk_freq); - if (client->name[6] == '4') { + if (state->ident != V4L2_IDENT_SAA7115) { /* status for the saa7114 */ reg1f = saa7115_read(client, 0x1f); signalOk = (reg1f & 0xc1) == 0x81; @@ -751,8 +812,8 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo u8 lcr[24]; int i, x; - /* saa7114 doesn't yet support VBI */ - if (state->ident == V4L2_IDENT_SAA7114) + /* saa7113/71144 doesn't yet support VBI */ + if (state->ident != V4L2_IDENT_SAA7115) return; for (i = 0; i <= 23; i++) @@ -791,7 +852,7 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo case 0: lcr[i] |= 0xf << (4 * x); break; - case V4L2_SLICED_TELETEXT_B: + case V4L2_SLICED_TELETEXT_PAL_B: lcr[i] |= 1 << (4 * x); break; case V4L2_SLICED_CAPTION_525: @@ -820,7 +881,7 @@ static void saa7115_set_lcr(struct i2c_client *client, struct v4l2_sliced_vbi_fo static int saa7115_get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt) { static u16 lcr2vbi[] = { - 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */ + 0, V4L2_SLICED_TELETEXT_PAL_B, 0, /* 1 */ 0, V4L2_SLICED_CAPTION_525, /* 4 */ V4L2_SLICED_WSS_625, 0, /* 5 */ V4L2_SLICED_VPS, 0, 0, 0, 0, /* 7 */ @@ -985,7 +1046,7 @@ static void saa7115_decode_vbi_line(struct i2c_client *client, /* decode payloads */ switch (id2) { case 1: - vbi->type = V4L2_SLICED_TELETEXT_B; + vbi->type = V4L2_SLICED_TELETEXT_PAL_B; break; case 4: if (!saa7115_odd_parity(p[0]) || !saa7115_odd_parity(p[1])) @@ -1261,14 +1322,12 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) saa7115_write(client, 0, 5); chip_id = saa7115_read(client, 0) & 0x0f; - if (chip_id != 4 && chip_id != 5) { + if (chip_id <3 && chip_id > 5) { v4l_dbg(1, debug, client, "saa7115 not found\n"); kfree(client); return 0; } - if (chip_id == 4) { - snprintf(client->name, sizeof(client->name) - 1, "saa7114"); - } + snprintf(client->name, sizeof(client->name) - 1, "saa711%d",chip_id); v4l_info(client, "saa711%d found @ 0x%x (%s)\n", chip_id, address << 1, adapter->name); state = kzalloc(sizeof(struct saa7115_state), GFP_KERNEL); @@ -1285,13 +1344,27 @@ static int saa7115_attach(struct i2c_adapter *adapter, int address, int kind) state->contrast = 64; state->hue = 0; state->sat = 64; - state->ident = (chip_id == 4) ? V4L2_IDENT_SAA7114 : V4L2_IDENT_SAA7115; + switch (chip_id) { + case 3: + state->ident = V4L2_IDENT_SAA7113; + break; + case 4: + state->ident = V4L2_IDENT_SAA7114; + break; + default: + state->ident = V4L2_IDENT_SAA7115; + break; + } + state->audclk_freq = 48000; v4l_dbg(1, debug, client, "writing init values\n"); /* init to 60hz/48khz */ - saa7115_writeregs(client, saa7115_init_auto_input); + if (state->ident==V4L2_IDENT_SAA7113) + saa7115_writeregs(client, saa7113_init_auto_input); + else + saa7115_writeregs(client, saa7115_init_auto_input); saa7115_writeregs(client, saa7115_init_misc); saa7115_writeregs(client, saa7115_cfg_60hz_fullres_x); saa7115_writeregs(client, saa7115_cfg_60hz_fullres_y); diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c index 7df5e0826e1..64e2c108df3 100644 --- a/drivers/media/video/saa7134/saa7134-alsa.c +++ b/drivers/media/video/saa7134/saa7134-alsa.c @@ -308,8 +308,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev) static int dsp_buffer_free(struct saa7134_dev *dev) { - if (!dev->dmasound.blksize) - BUG(); + BUG_ON(!dev->dmasound.blksize); videobuf_dma_free(&dev->dmasound.dma); @@ -611,12 +610,12 @@ static int snd_card_saa7134_capture_open(snd_pcm_substream_t * substream) struct saa7134_dev *dev = saa7134->dev; int err; - down(&dev->dmasound.lock); + mutex_lock(&dev->dmasound.lock); dev->dmasound.read_count = 0; dev->dmasound.read_offset = 0; - up(&dev->dmasound.lock); + mutex_unlock(&dev->dmasound.lock); pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); if (pcm == NULL) @@ -934,7 +933,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum) chip->irq = dev->pci->irq; - init_MUTEX(&dev->dmasound.lock); + mutex_init(&dev->dmasound.lock); if ((err = snd_card_saa7134_new_mixer(chip)) < 0) goto __nodev; diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c index 6bc63a4086c..fdd7f48f3b7 100644 --- a/drivers/media/video/saa7134/saa7134-cards.c +++ b/drivers/media/video/saa7134/saa7134-cards.c @@ -536,7 +536,7 @@ struct saa7134_board saa7134_boards[] = { .radio = { .name = name_radio, .amux = LINE2, - }, + }, }, [SAA7134_BOARD_MD7134] = { .name = "Medion 7134", @@ -640,6 +640,32 @@ struct saa7134_board saa7134_boards[] = { .tv = 1, }}, }, + [SAA7134_BOARD_ELSA_700TV] = { + .name = "ELSA EX-VISION 700TV", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_HITACHI_NTSC, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .inputs = {{ + .name = name_tv, + .vmux = 4, + .amux = LINE2, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 6, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 7, + .amux = LINE1, + }}, + .mute = { + .name = name_mute, + .amux = TV, + }, + }, [SAA7134_BOARD_ASUSTeK_TVFM7134] = { .name = "ASUS TV-FM 7134", .audio_clock = 0x00187de7, @@ -2002,7 +2028,7 @@ struct saa7134_board saa7134_boards[] = { [SAA7134_BOARD_FLYTV_DIGIMATRIX] = { .name = "FlyTV mini Asus Digimatrix", .audio_clock = 0x00200000, - .tuner_type = TUNER_LG_NTSC_TALN_MINI, + .tuner_type = TUNER_LG_TALN, .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, @@ -2598,6 +2624,7 @@ struct saa7134_board saa7134_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .gpiomask = 0x00200000, + .mpeg = SAA7134_MPEG_DVB, .inputs = {{ .name = name_tv, /* Analog broadcast/cable TV */ .vmux = 1, @@ -2623,6 +2650,164 @@ struct saa7134_board saa7134_boards[] = { .gpio = 0x000000, /* GPIO21=Low for FM radio antenna */ }, }, + [SAA7134_BOARD_AVERMEDIA_777] = { + .name = "AverTV DVB-T 777", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_comp1, + .vmux = 0, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_FLYDVBT_LR301] = { + /* LifeView FlyDVB-T */ + /* Giampiero Giancipoli <gianci@libero.it> */ + .name = "LifeView FlyDVB-T", + .audio_clock = 0x00200000, + .tuner_type = TUNER_ABSENT, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_comp1, /* Composite input */ + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, /* S-Video signal on S-Video input */ + .vmux = 8, + .amux = LINE2, + }}, + }, + [SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331] = { + .name = "ADS Instant TV Duo Cardbus PTV331", + .audio_clock = 0x00200000, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .gpiomask = 0x00600000, /* Bit 21 0=Radio, Bit 22 0=TV */ + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + .gpio = 0x00200000, + }}, + }, + [SAA7134_BOARD_TEVION_DVBT_220RF] = { + .name = "Tevion/KWorld DVB-T 220RF", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TDA8290, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE1, + },{ + .name = name_svideo, + .vmux = 0, + .amux = LINE1, + }}, + .radio = { + .name = name_radio, + .amux = LINE1, + }, + }, + [SAA7134_BOARD_KWORLD_ATSC110] = { + .name = "Kworld ATSC110", + .audio_clock = 0x00187de7, + .tuner_type = TUNER_PHILIPS_TUV1236D, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .mpeg = SAA7134_MPEG_DVB, + .inputs = {{ + .name = name_tv, + .vmux = 1, + .amux = TV, + .tv = 1, + },{ + .name = name_comp1, + .vmux = 3, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 8, + .amux = LINE2, + }}, + }, + [SAA7134_BOARD_AVERMEDIA_A169_B] = { + /* AVerMedia A169 */ + /* Rickard Osser <ricky@osser.se> */ + /* This card has two saa7134 chips on it, + but only one of them is currently working. */ + .name = "AVerMedia A169 B", + .audio_clock = 0x02187de7, + .tuner_type = TUNER_LG_TALN, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0x0a60000, + }, + [SAA7134_BOARD_AVERMEDIA_A169_B1] = { + /* AVerMedia A169 */ + /* Rickard Osser <ricky@osser.se> */ + .name = "AVerMedia A169 B1", + .audio_clock = 0x02187de7, + .tuner_type = TUNER_LG_TALN, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .tda9887_conf = TDA9887_PRESENT, + .gpiomask = 0xca60000, + .inputs = {{ + .name = name_tv, + .vmux = 4, + .amux = TV, + .tv = 1, + .gpio = 0x04a61000, + },{ + .name = name_comp2, /* Composite SVIDEO (B/W if signal is carried with SVIDEO) */ + .vmux = 1, + .amux = LINE2, + },{ + .name = name_svideo, + .vmux = 9, /* 9 is correct as S-VIDEO1 according to a169.inf! */ + .amux = LINE1, + }}, + }, + [SAA7134_BOARD_MD7134_BRIDGE_2] = { + /* This card has two saa7134 chips on it, + but only one of them is currently working. + The programming for the primary decoder is + in SAA7134_BOARD_MD7134 */ + .name = "Medion 7134 Bridge #2", + .audio_clock = 0x00187de7, + .radio_type = UNSET, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + }, }; const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards); @@ -2753,6 +2938,12 @@ struct pci_device_id saa7134_pci_tbl[] = { .driver_data = SAA7134_BOARD_ELSA_500TV, },{ .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7130, + .subvendor = 0x1048, + .subdevice = 0x226c, + .driver_data = SAA7134_BOARD_ELSA_700TV, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, .subvendor = PCI_VENDOR_ID_ASUSTEK, .subdevice = 0x4842, @@ -3094,6 +3285,54 @@ struct pci_device_id saa7134_pci_tbl[] = { .subdevice = 0x0319, .driver_data = SAA7134_BOARD_FLYDVB_TRIO, },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, /* SAA 7131E */ + .subvendor = 0x1461, + .subdevice = 0x2c05, + .driver_data = SAA7134_BOARD_AVERMEDIA_777, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x5168, + .subdevice = 0x0301, + .driver_data = SAA7134_BOARD_FLYDVBT_LR301, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x0331, + .subdevice = 0x1421, + .driver_data = SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, + .subvendor = 0x17de, + .subdevice = 0x7201, + .driver_data = SAA7134_BOARD_TEVION_DVBT_220RF, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7133, /* SAA7135HL */ + .subvendor = 0x17de, + .subdevice = 0x7350, + .driver_data = SAA7134_BOARD_KWORLD_ATSC110, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1461, + .subdevice = 0x7360, + .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x1461, + .subdevice = 0x6360, + .driver_data = SAA7134_BOARD_AVERMEDIA_A169_B1, + },{ + .vendor = PCI_VENDOR_ID_PHILIPS, + .device = PCI_DEVICE_ID_PHILIPS_SAA7134, + .subvendor = 0x16be, + .subdevice = 0x0005, + .driver_data = SAA7134_BOARD_MD7134_BRIDGE_2, + },{ /* --- boards without eeprom + subsystem ID --- */ .vendor = PCI_VENDOR_ID_PHILIPS, .device = PCI_DEVICE_ID_PHILIPS_SAA7134, @@ -3193,13 +3432,15 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_GOTVIEW_7135: case SAA7134_BOARD_KWORLD_TERMINATOR: case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS: + case SAA7134_BOARD_FLYDVBT_LR301: + case SAA7134_BOARD_FLYDVBTDUO: dev->has_remote = SAA7134_REMOTE_GPIO; break; case SAA7134_BOARD_MD5044: printk("%s: seems there are two different versions of the MD5044\n" - "%s: (with the same ID) out there. If sound doesn't work for\n" - "%s: you try the audio_clock_override=0x200000 insmod option.\n", - dev->name,dev->name,dev->name); + "%s: (with the same ID) out there. If sound doesn't work for\n" + "%s: you try the audio_clock_override=0x200000 insmod option.\n", + dev->name,dev->name,dev->name); break; case SAA7134_BOARD_CINERGY400_CARDBUS: /* power-up tuner chip */ @@ -3220,6 +3461,10 @@ int saa7134_board_init1(struct saa7134_dev *dev) saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06); break; + case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: + saa_writeb(SAA7134_GPIO_GPMODE3, 0x08); + saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x00); + break; case SAA7134_BOARD_AVERMEDIA_CARDBUS: /* power-up tuner chip */ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff); @@ -3242,6 +3487,13 @@ int saa7134_board_init1(struct saa7134_dev *dev) case SAA7134_BOARD_UPMOST_PURPLE_TV: dev->has_remote = SAA7134_REMOTE_I2C; break; + case SAA7134_BOARD_AVERMEDIA_A169_B: + case SAA7134_BOARD_MD7134_BRIDGE_2: + printk("%s: %s: dual saa713x broadcast decoders\n" + "%s: Sorry, none of the inputs to this chip are supported yet.\n" + "%s: Dual decoder functionality is disabled for now, use the other chip.\n", + dev->name,card(dev).name,dev->name,dev->name); + break; } return 0; } @@ -3362,14 +3614,44 @@ int saa7134_board_init2(struct saa7134_dev *dev) } break; case SAA7134_BOARD_PHILIPS_TIGER: + case SAA7134_BOARD_TEVION_DVBT_220RF: case SAA7134_BOARD_ASUSTeK_P7131_DUAL: - /* this is a hybrid board, initialize to analog mode */ + /* this is a hybrid board, initialize to analog mode + * and configure firmware eeprom address + */ { u8 data[] = { 0x3c, 0x33, 0x68}; struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; i2c_transfer(&dev->i2c_adap, &msg, 1); } break; + case SAA7134_BOARD_FLYDVB_TRIO: + { + u8 data[] = { 0x3c, 0x33, 0x62}; + struct i2c_msg msg = {.addr=0x09, .flags=0, .buf=data, .len = sizeof(data)}; + i2c_transfer(&dev->i2c_adap, &msg, 1); + } + break; + case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: + /* make the tda10046 find its eeprom */ + { + u8 data[] = { 0x3c, 0x33, 0x62}; + struct i2c_msg msg = {.addr=0x08, .flags=0, .buf=data, .len = sizeof(data)}; + i2c_transfer(&dev->i2c_adap, &msg, 1); + } + break; + case SAA7134_BOARD_KWORLD_ATSC110: + { + /* enable tuner */ + int i; + static const u8 buffer [] = { 0x10,0x12,0x13,0x04,0x16,0x00,0x14,0x04,0x017,0x00 }; + dev->i2c_client.addr = 0x0a; + for (i = 0; i < 5; i++) + if (2 != i2c_master_send(&dev->i2c_client,&buffer[i*2],2)) + printk(KERN_WARNING "%s: Unable to enable tuner(%i).\n", + dev->name, i); + } + break; } return 0; } diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 028904bd94a..58e568d7d2e 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -66,6 +66,11 @@ static unsigned int latency = UNSET; module_param(latency, int, 0444); MODULE_PARM_DESC(latency,"pci latency timer"); +int saa7134_no_overlay=-1; +module_param_named(no_overlay, saa7134_no_overlay, int, 0444); +MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" + " [some VIA/SIS chipsets are known to have problem with overlay]"); + static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; @@ -251,8 +256,7 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf) { - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma); @@ -613,7 +617,7 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) saa_writel(SAA7134_IRQ1, 0); saa_writel(SAA7134_IRQ2, 0); - init_MUTEX(&dev->lock); + mutex_init(&dev->lock); spin_lock_init(&dev->slock); saa7134_track_gpio(dev,"pre-init"); @@ -835,6 +839,22 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, latency = 0x0A; } #endif + if (pci_pci_problems & PCIPCI_FAIL) { + printk(KERN_INFO "%s: quirk: this driver and your " + "chipset may not work together" + " in overlay mode.\n",dev->name); + if (!saa7134_no_overlay) { + printk(KERN_INFO "%s: quirk: overlay " + "mode will be disabled.\n", + dev->name); + saa7134_no_overlay = 1; + } else { + printk(KERN_INFO "%s: quirk: overlay " + "mode will be forced. Use this" + " option at your own risk.\n", + dev->name); + } + } } if (UNSET != latency) { printk(KERN_INFO "%s: setting pci latency timer to %d\n", @@ -937,6 +957,11 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, v4l2_prio_init(&dev->prio); /* register v4l devices */ + if (saa7134_no_overlay <= 0) { + saa7134_video_template.type |= VID_TYPE_OVERLAY; + } else { + printk("bttv: Overlay support disabled.\n"); + } dev->video_dev = vdev_init(dev,&saa7134_video_template,"video"); err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[dev->nr]); diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c index 9db8e13f21c..86cfdb8514c 100644 --- a/drivers/media/video/saa7134/saa7134-dvb.c +++ b/drivers/media/video/saa7134/saa7134-dvb.c @@ -32,6 +32,7 @@ #include "saa7134-reg.h" #include "saa7134.h" #include <media/v4l2-common.h> +#include "dvb-pll.h" #ifdef HAVE_MT352 # include "mt352.h" @@ -42,7 +43,6 @@ #endif #ifdef HAVE_NXT200X # include "nxt200x.h" -# include "dvb-pll.h" #endif MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); @@ -114,6 +114,24 @@ static int mt352_pinnacle_init(struct dvb_frontend* fe) return 0; } +static int mt352_aver777_init(struct dvb_frontend* fe) +{ + static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d }; + static u8 reset [] = { RESET, 0x80 }; + static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; + static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 }; + static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 }; + + mt352_write(fe, clock_config, sizeof(clock_config)); + udelay(200); + mt352_write(fe, reset, sizeof(reset)); + mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg)); + mt352_write(fe, agc_cfg, sizeof(agc_cfg)); + mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg)); + + return 0; +} + static int mt352_pinnacle_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) @@ -146,6 +164,15 @@ static int mt352_pinnacle_pll_set(struct dvb_frontend* fe, return 0; } +static int mt352_aver777_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8* pllbuf) +{ + pllbuf[0] = 0xc2; + dvb_pll_configure(&dvb_pll_philips_td1316, pllbuf+1, + params->frequency, + params->u.ofdm.bandwidth); + return 0; +} + static struct mt352_config pinnacle_300i = { .demod_address = 0x3c >> 1, .adc_clock = 20333, @@ -154,6 +181,12 @@ static struct mt352_config pinnacle_300i = { .demod_init = mt352_pinnacle_init, .pll_set = mt352_pinnacle_pll_set, }; + +static struct mt352_config avermedia_777 = { + .demod_address = 0xf, + .demod_init = mt352_aver777_init, + .pll_set = mt352_aver777_pll_set, +}; #endif /* ------------------------------------------------------------------ */ @@ -781,7 +814,7 @@ static int philips_tiger_pll_set(struct dvb_frontend *fe, struct dvb_frontend_pa tda8290_msg.buf = tda8290_open; i2c_transfer(&dev->i2c_adap, &tda8290_msg, 1); return ret; -}; +} static int philips_tiger_dvb_mode(struct dvb_frontend *fe) { @@ -817,6 +850,110 @@ static struct tda1004x_config philips_tiger_config = { .request_firmware = NULL, }; +/* ------------------------------------------------------------------ */ + +static int lifeview_trio_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + int ret; + + ret = philips_tda827xa_pll_set(0x60, fe, params); + return ret; +} + +static int lifeview_trio_dvb_mode(struct dvb_frontend *fe) +{ + return 0; +} + +static void lifeview_trio_analog_mode(struct dvb_frontend *fe) +{ + philips_tda827xa_pll_sleep(0x60, fe); +} + +static struct tda1004x_config lifeview_trio_config = { + .demod_address = 0x09, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X_GPL, + .if_freq = TDA10046_FREQ_045, + .pll_init = lifeview_trio_dvb_mode, + .pll_set = lifeview_trio_pll_set, + .pll_sleep = lifeview_trio_analog_mode, + .request_firmware = NULL, +}; + +/* ------------------------------------------------------------------ */ + +static int ads_duo_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + int ret; + + ret = philips_tda827xa_pll_set(0x61, fe, params); + return ret; +} + +static int ads_duo_dvb_mode(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + /* route TDA8275a AGC input to the channel decoder */ + saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x60); + return 0; +} + +static void ads_duo_analog_mode(struct dvb_frontend *fe) +{ + struct saa7134_dev *dev = fe->dvb->priv; + /* route TDA8275a AGC input to the analog IF chip*/ + saa_writeb(SAA7134_GPIO_GPSTATUS2, 0x20); + philips_tda827xa_pll_sleep( 0x61, fe); +} + +static struct tda1004x_config ads_tech_duo_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X_GPL, + .if_freq = TDA10046_FREQ_045, + .pll_init = ads_duo_dvb_mode, + .pll_set = ads_duo_pll_set, + .pll_sleep = ads_duo_analog_mode, + .request_firmware = NULL, +}; + +/* ------------------------------------------------------------------ */ + +static int tevion_dvb220rf_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + int ret; + ret = philips_tda827xa_pll_set(0x60, fe, params); + return ret; +} + +static int tevion_dvb220rf_pll_init(struct dvb_frontend *fe) +{ + return 0; +} + +static void tevion_dvb220rf_pll_sleep(struct dvb_frontend *fe) +{ + philips_tda827xa_pll_sleep( 0x61, fe); +} + +static struct tda1004x_config tevion_dvbt220rf_config = { + .demod_address = 0x08, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_16M, + .agc_config = TDA10046_AGC_TDA827X, + .if_freq = TDA10046_FREQ_045, + .pll_init = tevion_dvb220rf_pll_init, + .pll_set = tevion_dvb220rf_pll_set, + .pll_sleep = tevion_dvb220rf_pll_sleep, + .request_firmware = NULL, +}; + #endif /* ------------------------------------------------------------------ */ @@ -827,6 +964,22 @@ static struct nxt200x_config avertvhda180 = { .pll_address = 0x61, .pll_desc = &dvb_pll_tdhu2, }; + +static int nxt200x_set_pll_input(u8 *buf, int input) +{ + if (input) + buf[3] |= 0x08; + else + buf[3] &= ~0x08; + return 0; +} + +static struct nxt200x_config kworldatsc110 = { + .demod_address = 0x0a, + .pll_address = 0x61, + .pll_desc = &dvb_pll_tuv1236d, + .set_pll_input = nxt200x_set_pll_input, +}; #endif /* ------------------------------------------------------------------ */ @@ -851,6 +1004,12 @@ static int dvb_init(struct saa7134_dev *dev) dev->dvb.frontend = mt352_attach(&pinnacle_300i, &dev->i2c_adap); break; + + case SAA7134_BOARD_AVERMEDIA_777: + printk("%s: avertv 777 dvb setup\n",dev->name); + dev->dvb.frontend = mt352_attach(&avermedia_777, + &dev->i2c_adap); + break; #endif #ifdef HAVE_TDA1004X case SAA7134_BOARD_MD7134: @@ -889,11 +1048,30 @@ static int dvb_init(struct saa7134_dev *dev) dev->dvb.frontend = tda10046_attach(&philips_tiger_config, &dev->i2c_adap); break; + case SAA7134_BOARD_FLYDVBT_LR301: + dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config, + &dev->i2c_adap); + break; + case SAA7134_BOARD_FLYDVB_TRIO: + dev->dvb.frontend = tda10046_attach(&lifeview_trio_config, + &dev->i2c_adap); + break; + case SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331: + dev->dvb.frontend = tda10046_attach(&ads_tech_duo_config, + &dev->i2c_adap); + break; + case SAA7134_BOARD_TEVION_DVBT_220RF: + dev->dvb.frontend = tda10046_attach(&tevion_dvbt220rf_config, + &dev->i2c_adap); + break; #endif #ifdef HAVE_NXT200X case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180: dev->dvb.frontend = nxt200x_attach(&avertvhda180, &dev->i2c_adap); break; + case SAA7134_BOARD_KWORLD_ATSC110: + dev->dvb.frontend = nxt200x_attach(&kworldatsc110, &dev->i2c_adap); + break; #endif default: printk("%s: Huh? unknown DVB card?\n",dev->name); diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index bd4c389d4c3..1d972edb3be 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -89,7 +89,7 @@ static int ts_open(struct inode *inode, struct file *file) dprintk("open minor=%d\n",minor); err = -EBUSY; - if (down_trylock(&dev->empress_tsq.lock)) + if (!mutex_trylock(&dev->empress_tsq.lock)) goto done; if (dev->empress_users) goto done_up; @@ -99,7 +99,7 @@ static int ts_open(struct inode *inode, struct file *file) err = 0; done_up: - up(&dev->empress_tsq.lock); + mutex_unlock(&dev->empress_tsq.lock); done: return err; } @@ -110,7 +110,7 @@ static int ts_release(struct inode *inode, struct file *file) if (dev->empress_tsq.streaming) videobuf_streamoff(&dev->empress_tsq); - down(&dev->empress_tsq.lock); + mutex_lock(&dev->empress_tsq.lock); if (dev->empress_tsq.reading) videobuf_read_stop(&dev->empress_tsq); videobuf_mmap_free(&dev->empress_tsq); @@ -119,7 +119,7 @@ static int ts_release(struct inode *inode, struct file *file) /* stop the encoder */ ts_reset_encoder(dev); - up(&dev->empress_tsq.lock); + mutex_unlock(&dev->empress_tsq.lock); return 0; } diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c index 82d28cbf289..1426e4c8602 100644 --- a/drivers/media/video/saa7134/saa7134-input.c +++ b/drivers/media/video/saa7134/saa7134-input.c @@ -42,485 +42,6 @@ MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]"); #define i2cdprintk(fmt, arg...) if (ir_debug) \ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg) -/* ---------------------------------------------------------------------- */ - -static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = { - [ 15 ] = KEY_KP0, - [ 3 ] = KEY_KP1, - [ 4 ] = KEY_KP2, - [ 5 ] = KEY_KP3, - [ 7 ] = KEY_KP4, - [ 8 ] = KEY_KP5, - [ 9 ] = KEY_KP6, - [ 11 ] = KEY_KP7, - [ 12 ] = KEY_KP8, - [ 13 ] = KEY_KP9, - - [ 14 ] = KEY_MODE, // Air/Cable - [ 17 ] = KEY_VIDEO, // Video - [ 21 ] = KEY_AUDIO, // Audio - [ 0 ] = KEY_POWER, // Power - [ 24 ] = KEY_TUNER, // AV Source - [ 2 ] = KEY_ZOOM, // Fullscreen - [ 26 ] = KEY_LANGUAGE, // Stereo - [ 27 ] = KEY_MUTE, // Mute - [ 20 ] = KEY_VOLUMEUP, // Volume + - [ 23 ] = KEY_VOLUMEDOWN, // Volume - - [ 18 ] = KEY_CHANNELUP, // Channel + - [ 19 ] = KEY_CHANNELDOWN, // Channel - - [ 6 ] = KEY_AGAIN, // Recall - [ 16 ] = KEY_ENTER, // Enter -}; - - -static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = { - [ 0 ] = KEY_KP0, - [ 1 ] = KEY_KP1, - [ 2 ] = KEY_KP2, - [ 3 ] = KEY_KP3, - [ 4 ] = KEY_KP4, - [ 5 ] = KEY_KP5, - [ 6 ] = KEY_KP6, - [ 7 ] = KEY_KP7, - [ 8 ] = KEY_KP8, - [ 9 ] = KEY_KP9, - - [ 0x0a ] = KEY_POWER, - [ 0x0b ] = KEY_PROG1, // app - [ 0x0c ] = KEY_ZOOM, // zoom/fullscreen - [ 0x0d ] = KEY_CHANNELUP, // channel - [ 0x0e ] = KEY_CHANNELDOWN, // channel- - [ 0x0f ] = KEY_VOLUMEUP, - [ 0x10 ] = KEY_VOLUMEDOWN, - [ 0x11 ] = KEY_TUNER, // AV - [ 0x12 ] = KEY_NUMLOCK, // -/-- - [ 0x13 ] = KEY_AUDIO, // audio - [ 0x14 ] = KEY_MUTE, - [ 0x15 ] = KEY_UP, - [ 0x16 ] = KEY_DOWN, - [ 0x17 ] = KEY_LEFT, - [ 0x18 ] = KEY_RIGHT, - [ 0x19 ] = BTN_LEFT, - [ 0x1a ] = BTN_RIGHT, - [ 0x1b ] = KEY_WWW, // text - [ 0x1c ] = KEY_REWIND, - [ 0x1d ] = KEY_FORWARD, - [ 0x1e ] = KEY_RECORD, - [ 0x1f ] = KEY_PLAY, - [ 0x20 ] = KEY_PREVIOUSSONG, - [ 0x21 ] = KEY_NEXTSONG, - [ 0x22 ] = KEY_PAUSE, - [ 0x23 ] = KEY_STOP, -}; - -/* Alfons Geser <a.geser@cox.net> - * updates from Job D. R. Borges <jobdrb@ig.com.br> */ -static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = { - [ 18 ] = KEY_POWER, - [ 1 ] = KEY_TV, // DVR - [ 21 ] = KEY_DVD, // DVD - [ 23 ] = KEY_AUDIO, // music - // DVR mode / DVD mode / music mode - - [ 27 ] = KEY_MUTE, // mute - [ 2 ] = KEY_LANGUAGE, // MTS/SAP / audio / autoseek - [ 30 ] = KEY_SUBTITLE, // closed captioning / subtitle / seek - [ 22 ] = KEY_ZOOM, // full screen - [ 28 ] = KEY_VIDEO, // video source / eject / delall - [ 29 ] = KEY_RESTART, // playback / angle / del - [ 47 ] = KEY_SEARCH, // scan / menu / playlist - [ 48 ] = KEY_CHANNEL, // CH surfing / bookmark / memo - - [ 49 ] = KEY_HELP, // help - [ 50 ] = KEY_MODE, // num/memo - [ 51 ] = KEY_ESC, // cancel - - [ 12 ] = KEY_UP, // up - [ 16 ] = KEY_DOWN, // down - [ 8 ] = KEY_LEFT, // left - [ 4 ] = KEY_RIGHT, // right - [ 3 ] = KEY_SELECT, // select - - [ 31 ] = KEY_REWIND, // rewind - [ 32 ] = KEY_PLAYPAUSE, // play/pause - [ 41 ] = KEY_FORWARD, // forward - [ 20 ] = KEY_AGAIN, // repeat - [ 43 ] = KEY_RECORD, // recording - [ 44 ] = KEY_STOP, // stop - [ 45 ] = KEY_PLAY, // play - [ 46 ] = KEY_SHUFFLE, // snapshot / shuffle - - [ 0 ] = KEY_KP0, - [ 5 ] = KEY_KP1, - [ 6 ] = KEY_KP2, - [ 7 ] = KEY_KP3, - [ 9 ] = KEY_KP4, - [ 10 ] = KEY_KP5, - [ 11 ] = KEY_KP6, - [ 13 ] = KEY_KP7, - [ 14 ] = KEY_KP8, - [ 15 ] = KEY_KP9, - - [ 42 ] = KEY_VOLUMEUP, - [ 17 ] = KEY_VOLUMEDOWN, - [ 24 ] = KEY_CHANNELUP, // CH.tracking up - [ 25 ] = KEY_CHANNELDOWN, // CH.tracking down - - [ 19 ] = KEY_KPENTER, // enter - [ 33 ] = KEY_KPDOT, // . (decimal dot) -}; - -static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = { - [ 30 ] = KEY_POWER, // power - [ 28 ] = KEY_SEARCH, // scan - [ 7 ] = KEY_SELECT, // source - - [ 22 ] = KEY_VOLUMEUP, - [ 20 ] = KEY_VOLUMEDOWN, - [ 31 ] = KEY_CHANNELUP, - [ 23 ] = KEY_CHANNELDOWN, - [ 24 ] = KEY_MUTE, - - [ 2 ] = KEY_KP0, - [ 1 ] = KEY_KP1, - [ 11 ] = KEY_KP2, - [ 27 ] = KEY_KP3, - [ 5 ] = KEY_KP4, - [ 9 ] = KEY_KP5, - [ 21 ] = KEY_KP6, - [ 6 ] = KEY_KP7, - [ 10 ] = KEY_KP8, - [ 18 ] = KEY_KP9, - [ 16 ] = KEY_KPDOT, - - [ 3 ] = KEY_TUNER, // tv/fm - [ 4 ] = KEY_REWIND, // fm tuning left or function left - [ 12 ] = KEY_FORWARD, // fm tuning right or function right - - [ 0 ] = KEY_RECORD, - [ 8 ] = KEY_STOP, - [ 17 ] = KEY_PLAY, - - [ 25 ] = KEY_ZOOM, - [ 14 ] = KEY_MENU, // function - [ 19 ] = KEY_AGAIN, // recall - [ 29 ] = KEY_RESTART, // reset - [ 26 ] = KEY_SHUFFLE, // snapshot/shuffle - -// FIXME - [ 13 ] = KEY_F21, // mts - [ 15 ] = KEY_F22, // min -}; - -/* Alex Hermann <gaaf@gmx.net> */ -static IR_KEYTAB_TYPE md2819_codes[IR_KEYTAB_SIZE] = { - [ 40 ] = KEY_KP1, - [ 24 ] = KEY_KP2, - [ 56 ] = KEY_KP3, - [ 36 ] = KEY_KP4, - [ 20 ] = KEY_KP5, - [ 52 ] = KEY_KP6, - [ 44 ] = KEY_KP7, - [ 28 ] = KEY_KP8, - [ 60 ] = KEY_KP9, - [ 34 ] = KEY_KP0, - - [ 32 ] = KEY_TV, // TV/FM - [ 16 ] = KEY_CD, // CD - [ 48 ] = KEY_TEXT, // TELETEXT - [ 0 ] = KEY_POWER, // POWER - - [ 8 ] = KEY_VIDEO, // VIDEO - [ 4 ] = KEY_AUDIO, // AUDIO - [ 12 ] = KEY_ZOOM, // FULL SCREEN - - [ 18 ] = KEY_SUBTITLE, // DISPLAY - ??? - [ 50 ] = KEY_REWIND, // LOOP - ??? - [ 2 ] = KEY_PRINT, // PREVIEW - ??? - - [ 42 ] = KEY_SEARCH, // AUTOSCAN - [ 26 ] = KEY_SLEEP, // FREEZE - ??? - [ 58 ] = KEY_SHUFFLE, // SNAPSHOT - ??? - [ 10 ] = KEY_MUTE, // MUTE - - [ 38 ] = KEY_RECORD, // RECORD - [ 22 ] = KEY_PAUSE, // PAUSE - [ 54 ] = KEY_STOP, // STOP - [ 6 ] = KEY_PLAY, // PLAY - - [ 46 ] = KEY_RED, // <RED> - [ 33 ] = KEY_GREEN, // <GREEN> - [ 14 ] = KEY_YELLOW, // <YELLOW> - [ 1 ] = KEY_BLUE, // <BLUE> - - [ 30 ] = KEY_VOLUMEDOWN, // VOLUME- - [ 62 ] = KEY_VOLUMEUP, // VOLUME+ - [ 17 ] = KEY_CHANNELDOWN, // CHANNEL/PAGE- - [ 49 ] = KEY_CHANNELUP // CHANNEL/PAGE+ -}; - -static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = { - [ 20 ] = KEY_MUTE, - [ 36 ] = KEY_ZOOM, - - [ 1 ] = KEY_DVD, - [ 35 ] = KEY_RADIO, - [ 0 ] = KEY_TV, - - [ 10 ] = KEY_REWIND, - [ 8 ] = KEY_PLAYPAUSE, - [ 15 ] = KEY_FORWARD, - - [ 2 ] = KEY_PREVIOUS, - [ 7 ] = KEY_STOP, - [ 6 ] = KEY_NEXT, - - [ 12 ] = KEY_UP, - [ 14 ] = KEY_DOWN, - [ 11 ] = KEY_LEFT, - [ 13 ] = KEY_RIGHT, - [ 17 ] = KEY_OK, - - [ 3 ] = KEY_MENU, - [ 9 ] = KEY_SETUP, - [ 5 ] = KEY_VIDEO, - [ 34 ] = KEY_CHANNEL, - - [ 18 ] = KEY_VOLUMEUP, - [ 21 ] = KEY_VOLUMEDOWN, - [ 16 ] = KEY_CHANNELUP, - [ 19 ] = KEY_CHANNELDOWN, - - [ 4 ] = KEY_RECORD, - - [ 22 ] = KEY_KP1, - [ 23 ] = KEY_KP2, - [ 24 ] = KEY_KP3, - [ 25 ] = KEY_KP4, - [ 26 ] = KEY_KP5, - [ 27 ] = KEY_KP6, - [ 28 ] = KEY_KP7, - [ 29 ] = KEY_KP8, - [ 30 ] = KEY_KP9, - [ 31 ] = KEY_KP0, - - [ 32 ] = KEY_LANGUAGE, - [ 33 ] = KEY_SLEEP, -}; - -/* Michael Tokarev <mjt@tls.msk.ru> - http://www.corpit.ru/mjt/beholdTV/remote_control.jpg - keytable is used by MANLI MTV00[12] and BeholdTV 40[13] at - least, and probably other cards too. - The "ascii-art picture" below (in comments, first row - is the keycode in hex, and subsequent row(s) shows - the button labels (several variants when appropriate) - helps to descide which keycodes to assign to the buttons. - */ -static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = { - - /* 0x1c 0x12 * - * FUNCTION POWER * - * FM (|) * - * */ - [ 0x1c ] = KEY_RADIO, /*XXX*/ - [ 0x12 ] = KEY_POWER, - - /* 0x01 0x02 0x03 * - * 1 2 3 * - * * - * 0x04 0x05 0x06 * - * 4 5 6 * - * * - * 0x07 0x08 0x09 * - * 7 8 9 * - * */ - [ 0x01 ] = KEY_KP1, - [ 0x02 ] = KEY_KP2, - [ 0x03 ] = KEY_KP3, - [ 0x04 ] = KEY_KP4, - [ 0x05 ] = KEY_KP5, - [ 0x06 ] = KEY_KP6, - [ 0x07 ] = KEY_KP7, - [ 0x08 ] = KEY_KP8, - [ 0x09 ] = KEY_KP9, - - /* 0x0a 0x00 0x17 * - * RECALL 0 +100 * - * PLUS * - * */ - [ 0x0a ] = KEY_AGAIN, /*XXX KEY_REWIND? */ - [ 0x00 ] = KEY_KP0, - [ 0x17 ] = KEY_DIGITS, /*XXX*/ - - /* 0x14 0x10 * - * MENU INFO * - * OSD */ - [ 0x14 ] = KEY_MENU, - [ 0x10 ] = KEY_INFO, - - /* 0x0b * - * Up * - * * - * 0x18 0x16 0x0c * - * Left Ok Right * - * * - * 0x015 * - * Down * - * */ - [ 0x0b ] = KEY_UP, /*XXX KEY_SCROLLUP? */ - [ 0x18 ] = KEY_LEFT, /*XXX KEY_BACK? */ - [ 0x16 ] = KEY_OK, /*XXX KEY_SELECT? KEY_ENTER? */ - [ 0x0c ] = KEY_RIGHT, /*XXX KEY_FORWARD? */ - [ 0x15 ] = KEY_DOWN, /*XXX KEY_SCROLLDOWN? */ - - /* 0x11 0x0d * - * TV/AV MODE * - * SOURCE STEREO * - * */ - [ 0x11 ] = KEY_TV, /*XXX*/ - [ 0x0d ] = KEY_MODE, /*XXX there's no KEY_STEREO */ - - /* 0x0f 0x1b 0x1a * - * AUDIO Vol+ Chan+ * - * TIMESHIFT??? * - * * - * 0x0e 0x1f 0x1e * - * SLEEP Vol- Chan- * - * */ - [ 0x0f ] = KEY_AUDIO, - [ 0x1b ] = KEY_VOLUMEUP, - [ 0x1a ] = KEY_CHANNELUP, - [ 0x0e ] = KEY_SLEEP, /*XXX maybe KEY_PAUSE */ - [ 0x1f ] = KEY_VOLUMEDOWN, - [ 0x1e ] = KEY_CHANNELDOWN, - - /* 0x13 0x19 * - * MUTE SNAPSHOT* - * */ - [ 0x13 ] = KEY_MUTE, - [ 0x19 ] = KEY_RECORD, /*XXX*/ - - // 0x1d unused ? -}; - - -/* Mike Baikov <mike@baikov.com> */ -static IR_KEYTAB_TYPE gotview7135_codes[IR_KEYTAB_SIZE] = { - - [ 33 ] = KEY_POWER, - [ 105] = KEY_TV, - [ 51 ] = KEY_KP0, - [ 81 ] = KEY_KP1, - [ 49 ] = KEY_KP2, - [ 113] = KEY_KP3, - [ 59 ] = KEY_KP4, - [ 88 ] = KEY_KP5, - [ 65 ] = KEY_KP6, - [ 72 ] = KEY_KP7, - [ 48 ] = KEY_KP8, - [ 83 ] = KEY_KP9, - [ 115] = KEY_AGAIN, /* LOOP */ - [ 10 ] = KEY_AUDIO, - [ 97 ] = KEY_PRINT, /* PREVIEW */ - [ 122] = KEY_VIDEO, - [ 32 ] = KEY_CHANNELUP, - [ 64 ] = KEY_CHANNELDOWN, - [ 24 ] = KEY_VOLUMEDOWN, - [ 80 ] = KEY_VOLUMEUP, - [ 16 ] = KEY_MUTE, - [ 74 ] = KEY_SEARCH, - [ 123] = KEY_SHUFFLE, /* SNAPSHOT */ - [ 34 ] = KEY_RECORD, - [ 98 ] = KEY_STOP, - [ 120] = KEY_PLAY, - [ 57 ] = KEY_REWIND, - [ 89 ] = KEY_PAUSE, - [ 25 ] = KEY_FORWARD, - [ 9 ] = KEY_ZOOM, - - [ 82 ] = KEY_F21, /* LIVE TIMESHIFT */ - [ 26 ] = KEY_F22, /* MIN TIMESHIFT */ - [ 58 ] = KEY_F23, /* TIMESHIFT */ - [ 112] = KEY_F24, /* NORMAL TIMESHIFT */ -}; - -static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = { - [ 0x3 ] = KEY_POWER, - [ 0x6f ] = KEY_MUTE, - [ 0x10 ] = KEY_BACKSPACE, /* Recall */ - - [ 0x11 ] = KEY_KP0, - [ 0x4 ] = KEY_KP1, - [ 0x5 ] = KEY_KP2, - [ 0x6 ] = KEY_KP3, - [ 0x8 ] = KEY_KP4, - [ 0x9 ] = KEY_KP5, - [ 0xa ] = KEY_KP6, - [ 0xc ] = KEY_KP7, - [ 0xd ] = KEY_KP8, - [ 0xe ] = KEY_KP9, - [ 0x12 ] = KEY_KPDOT, /* 100+ */ - - [ 0x7 ] = KEY_VOLUMEUP, - [ 0xb ] = KEY_VOLUMEDOWN, - [ 0x1a ] = KEY_KPPLUS, - [ 0x18 ] = KEY_KPMINUS, - [ 0x15 ] = KEY_UP, - [ 0x1d ] = KEY_DOWN, - [ 0xf ] = KEY_CHANNELUP, - [ 0x13 ] = KEY_CHANNELDOWN, - [ 0x48 ] = KEY_ZOOM, - - [ 0x1b ] = KEY_VIDEO, /* Video source */ - [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */ - [ 0x19 ] = KEY_SEARCH, /* Auto Scan */ - - [ 0x4b ] = KEY_RECORD, - [ 0x46 ] = KEY_PLAY, - [ 0x45 ] = KEY_PAUSE, /* Pause */ - [ 0x44 ] = KEY_STOP, - [ 0x40 ] = KEY_FORWARD, /* Forward ? */ - [ 0x42 ] = KEY_REWIND, /* Backward ? */ - -}; - -/* Mapping for the 28 key remote control as seen at - http://www.sednacomputer.com/photo/cardbus-tv.jpg - Pavel Mihaylov <bin@bash.info> */ -static IR_KEYTAB_TYPE pctv_sedna_codes[IR_KEYTAB_SIZE] = { - [ 0 ] = KEY_KP0, - [ 1 ] = KEY_KP1, - [ 2 ] = KEY_KP2, - [ 3 ] = KEY_KP3, - [ 4 ] = KEY_KP4, - [ 5 ] = KEY_KP5, - [ 6 ] = KEY_KP6, - [ 7 ] = KEY_KP7, - [ 8 ] = KEY_KP8, - [ 9 ] = KEY_KP9, - - [ 0x0a ] = KEY_AGAIN, /* Recall */ - [ 0x0b ] = KEY_CHANNELUP, - [ 0x0c ] = KEY_VOLUMEUP, - [ 0x0d ] = KEY_MODE, /* Stereo */ - [ 0x0e ] = KEY_STOP, - [ 0x0f ] = KEY_PREVIOUSSONG, - [ 0x10 ] = KEY_ZOOM, - [ 0x11 ] = KEY_TUNER, /* Source */ - [ 0x12 ] = KEY_POWER, - [ 0x13 ] = KEY_MUTE, - [ 0x15 ] = KEY_CHANNELDOWN, - [ 0x18 ] = KEY_VOLUMEDOWN, - [ 0x19 ] = KEY_SHUFFLE, /* Snapshot */ - [ 0x1a ] = KEY_NEXTSONG, - [ 0x1b ] = KEY_TEXT, /* Time Shift */ - [ 0x1c ] = KEY_RADIO, /* FM Radio */ - [ 0x1d ] = KEY_RECORD, - [ 0x1e ] = KEY_PAUSE, -}; - - /* -------------------- GPIO generic keycode builder -------------------- */ static int build_key(struct saa7134_dev *dev) @@ -628,27 +149,27 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_FLYVIDEO3000: case SAA7134_BOARD_FLYTVPLATINUM_FM: case SAA7134_BOARD_FLYTVPLATINUM_MINI2: - ir_codes = flyvideo_codes; + ir_codes = ir_codes_flyvideo; mask_keycode = 0xEC00000; mask_keydown = 0x0040000; break; case SAA7134_BOARD_CINERGY400: case SAA7134_BOARD_CINERGY600: case SAA7134_BOARD_CINERGY600_MK3: - ir_codes = cinergy_codes; + ir_codes = ir_codes_cinergy; mask_keycode = 0x00003f; mask_keyup = 0x040000; break; case SAA7134_BOARD_ECS_TVP3XP: case SAA7134_BOARD_ECS_TVP3XP_4CB5: - ir_codes = eztv_codes; + ir_codes = ir_codes_eztv; mask_keycode = 0x00017c; mask_keyup = 0x000002; polling = 50; // ms break; case SAA7134_BOARD_KWORLD_XPERT: case SAA7134_BOARD_AVACSSMARTTV: - ir_codes = avacssmart_codes; + ir_codes = ir_codes_pixelview; mask_keycode = 0x00001F; mask_keyup = 0x000020; polling = 50; // ms @@ -660,7 +181,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_AVERMEDIA_STUDIO_305: case SAA7134_BOARD_AVERMEDIA_STUDIO_307: case SAA7134_BOARD_AVERMEDIA_GO_007_FM: - ir_codes = md2819_codes; + ir_codes = ir_codes_avermedia; mask_keycode = 0x0007C8; mask_keydown = 0x000010; polling = 50; // ms @@ -669,7 +190,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4); break; case SAA7134_BOARD_KWORLD_TERMINATOR: - ir_codes = avacssmart_codes; + ir_codes = ir_codes_pixelview; mask_keycode = 0x00001f; mask_keyup = 0x000060; polling = 50; // ms @@ -677,19 +198,19 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_MANLI_MTV001: case SAA7134_BOARD_MANLI_MTV002: case SAA7134_BOARD_BEHOLD_409FM: - ir_codes = manli_codes; + ir_codes = ir_codes_manli; mask_keycode = 0x001f00; mask_keyup = 0x004000; polling = 50; // ms break; case SAA7134_BOARD_SEDNA_PC_TV_CARDBUS: - ir_codes = pctv_sedna_codes; + ir_codes = ir_codes_pctv_sedna; mask_keycode = 0x001f00; mask_keyup = 0x004000; polling = 50; // ms break; case SAA7134_BOARD_GOTVIEW_7135: - ir_codes = gotview7135_codes; + ir_codes = ir_codes_gotview7135; mask_keycode = 0x0003EC; mask_keyup = 0x008000; mask_keydown = 0x000010; @@ -698,17 +219,23 @@ int saa7134_input_init1(struct saa7134_dev *dev) case SAA7134_BOARD_VIDEOMATE_TV_PVR: case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS: case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII: - ir_codes = videomate_tv_pvr_codes; + ir_codes = ir_codes_videomate_tv_pvr; mask_keycode = 0x00003F; mask_keyup = 0x400000; polling = 50; // ms break; case SAA7134_BOARD_VIDEOMATE_DVBT_300: case SAA7134_BOARD_VIDEOMATE_DVBT_200: - ir_codes = videomate_tv_pvr_codes; + ir_codes = ir_codes_videomate_tv_pvr; mask_keycode = 0x003F00; mask_keyup = 0x040000; break; + case SAA7134_BOARD_FLYDVBT_LR301: + case SAA7134_BOARD_FLYDVBTDUO: + ir_codes = ir_codes_flydvb; + mask_keycode = 0x0001F00; + mask_keydown = 0x0040000; + break; } if (NULL == ir_codes) { printk("%s: Oops: IR config error [card=%d]\n", diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c index 7448e386a80..d79d05f8870 100644 --- a/drivers/media/video/saa7134/saa7134-oss.c +++ b/drivers/media/video/saa7134/saa7134-oss.c @@ -84,8 +84,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev) { int err; - if (!dev->dmasound.bufsize) - BUG(); + BUG_ON(!dev->dmasound.bufsize); videobuf_dma_init(&dev->dmasound.dma); err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE, (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT); @@ -96,8 +95,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev) static int dsp_buffer_free(struct saa7134_dev *dev) { - if (!dev->dmasound.blksize) - BUG(); + BUG_ON(!dev->dmasound.blksize); videobuf_dma_free(&dev->dmasound.dma); dev->dmasound.blocks = 0; dev->dmasound.blksize = 0; @@ -254,7 +252,7 @@ static int dsp_open(struct inode *inode, struct file *file) if (NULL == dev) return -ENODEV; - down(&dev->dmasound.lock); + mutex_lock(&dev->dmasound.lock); err = -EBUSY; if (dev->dmasound.users_dsp) goto fail1; @@ -270,13 +268,13 @@ static int dsp_open(struct inode *inode, struct file *file) if (0 != err) goto fail2; - up(&dev->dmasound.lock); + mutex_unlock(&dev->dmasound.lock); return 0; fail2: dev->dmasound.users_dsp--; fail1: - up(&dev->dmasound.lock); + mutex_unlock(&dev->dmasound.lock); return err; } @@ -284,13 +282,13 @@ static int dsp_release(struct inode *inode, struct file *file) { struct saa7134_dev *dev = file->private_data; - down(&dev->dmasound.lock); + mutex_lock(&dev->dmasound.lock); if (dev->dmasound.recording_on) dsp_rec_stop(dev); dsp_buffer_free(dev); dev->dmasound.users_dsp--; file->private_data = NULL; - up(&dev->dmasound.lock); + mutex_unlock(&dev->dmasound.lock); return 0; } @@ -304,7 +302,7 @@ static ssize_t dsp_read(struct file *file, char __user *buffer, int err,ret = 0; add_wait_queue(&dev->dmasound.wq, &wait); - down(&dev->dmasound.lock); + mutex_lock(&dev->dmasound.lock); while (count > 0) { /* wait for data if needed */ if (0 == dev->dmasound.read_count) { @@ -328,12 +326,12 @@ static ssize_t dsp_read(struct file *file, char __user *buffer, ret = -EAGAIN; break; } - up(&dev->dmasound.lock); + mutex_unlock(&dev->dmasound.lock); set_current_state(TASK_INTERRUPTIBLE); if (0 == dev->dmasound.read_count) schedule(); set_current_state(TASK_RUNNING); - down(&dev->dmasound.lock); + mutex_lock(&dev->dmasound.lock); if (signal_pending(current)) { if (0 == ret) ret = -EINTR; @@ -362,7 +360,7 @@ static ssize_t dsp_read(struct file *file, char __user *buffer, if (dev->dmasound.read_offset == dev->dmasound.bufsize) dev->dmasound.read_offset = 0; } - up(&dev->dmasound.lock); + mutex_unlock(&dev->dmasound.lock); remove_wait_queue(&dev->dmasound.wq, &wait); return ret; } @@ -435,13 +433,13 @@ static int dsp_ioctl(struct inode *inode, struct file *file, case SNDCTL_DSP_STEREO: if (get_user(val, p)) return -EFAULT; - down(&dev->dmasound.lock); + mutex_lock(&dev->dmasound.lock); dev->dmasound.channels = val ? 2 : 1; if (dev->dmasound.recording_on) { dsp_rec_stop(dev); dsp_rec_start(dev); } - up(&dev->dmasound.lock); + mutex_unlock(&dev->dmasound.lock); return put_user(dev->dmasound.channels-1, p); case SNDCTL_DSP_CHANNELS: @@ -449,13 +447,13 @@ static int dsp_ioctl(struct inode *inode, struct file *file, return -EFAULT; if (val != 1 && val != 2) return -EINVAL; - down(&dev->dmasound.lock); + mutex_lock(&dev->dmasound.lock); dev->dmasound.channels = val; if (dev->dmasound.recording_on) { dsp_rec_stop(dev); dsp_rec_start(dev); } - up(&dev->dmasound.lock); + mutex_unlock(&dev->dmasound.lock); /* fall through */ case SOUND_PCM_READ_CHANNELS: return put_user(dev->dmasound.channels, p); @@ -478,13 +476,13 @@ static int dsp_ioctl(struct inode *inode, struct file *file, case AFMT_U16_BE: case AFMT_S16_LE: case AFMT_S16_BE: - down(&dev->dmasound.lock); + mutex_lock(&dev->dmasound.lock); dev->dmasound.afmt = val; if (dev->dmasound.recording_on) { dsp_rec_stop(dev); dsp_rec_start(dev); } - up(&dev->dmasound.lock); + mutex_unlock(&dev->dmasound.lock); return put_user(dev->dmasound.afmt, p); default: return -EINVAL; @@ -509,10 +507,10 @@ static int dsp_ioctl(struct inode *inode, struct file *file, return 0; case SNDCTL_DSP_RESET: - down(&dev->dmasound.lock); + mutex_lock(&dev->dmasound.lock); if (dev->dmasound.recording_on) dsp_rec_stop(dev); - up(&dev->dmasound.lock); + mutex_unlock(&dev->dmasound.lock); return 0; case SNDCTL_DSP_GETBLKSIZE: return put_user(dev->dmasound.blksize, p); @@ -556,10 +554,10 @@ static unsigned int dsp_poll(struct file *file, struct poll_table_struct *wait) poll_wait(file, &dev->dmasound.wq, wait); if (0 == dev->dmasound.read_count) { - down(&dev->dmasound.lock); + mutex_lock(&dev->dmasound.lock); if (!dev->dmasound.recording_on) dsp_rec_start(dev); - up(&dev->dmasound.lock); + mutex_unlock(&dev->dmasound.lock); } else mask |= (POLLIN | POLLRDNORM); return mask; @@ -852,7 +850,7 @@ int saa7134_oss_init1(struct saa7134_dev *dev) return -1; /* general */ - init_MUTEX(&dev->dmasound.lock); + mutex_init(&dev->dmasound.lock); init_waitqueue_head(&dev->dmasound.wq); switch (dev->pci->device) { diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c index afa4dcb3f96..3043233a8b6 100644 --- a/drivers/media/video/saa7134/saa7134-tvaudio.c +++ b/drivers/media/video/saa7134/saa7134-tvaudio.c @@ -140,6 +140,12 @@ static struct saa7134_tvaudio tvaudio[] = { .carr2 = 5850, .mode = TVAUDIO_NICAM_AM, },{ + .name = "SECAM-L MONO", + .std = V4L2_STD_SECAM, + .carr1 = 6500, + .carr2 = -1, + .mode = TVAUDIO_AM_MONO, + },{ .name = "SECAM-D/K", .std = V4L2_STD_SECAM, .carr1 = 6500, @@ -334,6 +340,12 @@ static void tvaudio_setmode(struct saa7134_dev *dev, saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa1); saa_writeb(SAA7134_NICAM_CONFIG, 0x00); break; + case TVAUDIO_AM_MONO: + saa_writeb(SAA7134_DEMODULATOR, 0x12); + saa_writeb(SAA7134_DCXO_IDENT_CTRL, 0x00); + saa_writeb(SAA7134_FM_DEEMPHASIS, 0x44); + saa_writeb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0xa0); + break; case TVAUDIO_FM_SAT_STEREO: /* not implemented (yet) */ break; @@ -414,6 +426,7 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au switch (audio->mode) { case TVAUDIO_FM_MONO: + case TVAUDIO_AM_MONO: return V4L2_TUNER_SUB_MONO; case TVAUDIO_FM_K_STEREO: case TVAUDIO_FM_BG_STEREO: @@ -480,6 +493,7 @@ static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au switch (audio->mode) { case TVAUDIO_FM_MONO: + case TVAUDIO_AM_MONO: /* nothing to do ... */ break; case TVAUDIO_FM_K_STEREO: diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c index e97426bc85d..57a11e71d99 100644 --- a/drivers/media/video/saa7134/saa7134-video.c +++ b/drivers/media/video/saa7134/saa7134-video.c @@ -460,17 +460,17 @@ static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int return 1; /* is it free? */ - down(&dev->lock); + mutex_lock(&dev->lock); if (dev->resources & bit) { /* no, someone else uses it */ - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; } /* it's free, grab it */ fh->resources |= bit; dev->resources |= bit; dprintk("res: get %d\n",bit); - up(&dev->lock); + mutex_unlock(&dev->lock); return 1; } @@ -489,14 +489,13 @@ int res_locked(struct saa7134_dev *dev, unsigned int bit) static void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits) { - if ((fh->resources & bits) != bits) - BUG(); + BUG_ON((fh->resources & bits) != bits); - down(&dev->lock); + mutex_lock(&dev->lock); fh->resources &= ~bits; dev->resources &= ~bits; dprintk("res: put %d\n",bits); - up(&dev->lock); + mutex_unlock(&dev->lock); } /* ------------------------------------------------------------------ */ @@ -1340,21 +1339,21 @@ video_poll(struct file *file, struct poll_table_struct *wait) if (!list_empty(&fh->cap.stream)) buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream); } else { - down(&fh->cap.lock); + mutex_lock(&fh->cap.lock); if (UNSET == fh->cap.read_off) { /* need to capture a new frame */ if (res_locked(fh->dev,RESOURCE_VIDEO)) { - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return POLLERR; } if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) { - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); return POLLERR; } fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf); fh->cap.read_off = 0; } - up(&fh->cap.lock); + mutex_unlock(&fh->cap.lock); buf = fh->cap.read_buf; } @@ -1463,6 +1462,10 @@ static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, f->fmt.pix.height * f->fmt.pix.bytesperline; return 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } f->fmt.win = fh->win; return 0; case V4L2_BUF_TYPE_VBI_CAPTURE: @@ -1527,6 +1530,10 @@ static int saa7134_try_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, return 0; } case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } err = verify_preview(dev,&f->fmt.win); if (0 != err) return err; @@ -1557,18 +1564,22 @@ static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, fh->cap.field = f->fmt.pix.field; return 0; case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } err = verify_preview(dev,&f->fmt.win); if (0 != err) return err; - down(&dev->lock); + mutex_lock(&dev->lock); fh->win = f->fmt.win; fh->nclips = f->fmt.win.clipcount; if (fh->nclips > 8) fh->nclips = 8; if (copy_from_user(fh->clips,f->fmt.win.clips, sizeof(struct v4l2_clip)*fh->nclips)) { - up(&dev->lock); + mutex_unlock(&dev->lock); return -EFAULT; } @@ -1578,7 +1589,7 @@ static int saa7134_s_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh, start_preview(dev,fh); spin_unlock_irqrestore(&dev->slock,flags); } - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; case V4L2_BUF_TYPE_VBI_CAPTURE: saa7134_vbi_fmt(dev,f); @@ -1612,9 +1623,9 @@ int saa7134_common_ioctl(struct saa7134_dev *dev, return get_control(dev,arg); case VIDIOC_S_CTRL: { - down(&dev->lock); + mutex_lock(&dev->lock); err = set_control(dev,NULL,arg); - up(&dev->lock); + mutex_unlock(&dev->lock); return err; } /* --- input switching --------------------------------------- */ @@ -1664,9 +1675,9 @@ int saa7134_common_ioctl(struct saa7134_dev *dev, return -EINVAL; if (NULL == card_in(dev,*i).name) return -EINVAL; - down(&dev->lock); + mutex_lock(&dev->lock); video_mux(dev,*i); - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; } @@ -1716,11 +1727,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file, cap->version = SAA7134_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_TUNER; + if (saa7134_no_overlay <= 0) { + cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY; + } if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET)) cap->capabilities &= ~V4L2_CAP_TUNER; @@ -1766,7 +1779,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, if (i == TVNORMS) return -EINVAL; - down(&dev->lock); + mutex_lock(&dev->lock); if (res_check(fh, RESOURCE_OVERLAY)) { spin_lock_irqsave(&dev->slock,flags); stop_preview(dev,fh); @@ -1776,7 +1789,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file, } else set_tvnorm(dev,&tvnorms[i]); saa7134_tvaudio_do_scan(dev); - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; } @@ -1909,13 +1922,13 @@ static int video_do_ioctl(struct inode *inode, struct file *file, return -EINVAL; if (1 == fh->radio && V4L2_TUNER_RADIO != f->type) return -EINVAL; - down(&dev->lock); + mutex_lock(&dev->lock); dev->ctl_freq = f->frequency; saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f); saa7134_tvaudio_do_scan(dev); - up(&dev->lock); + mutex_unlock(&dev->lock); return 0; } @@ -1971,6 +1984,10 @@ static int video_do_ioctl(struct inode *inode, struct file *file, switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (saa7134_no_overlay > 0) { + printk ("V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n"); + return -EINVAL; + } if (index >= FORMATS) return -EINVAL; if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY && @@ -2031,6 +2048,11 @@ static int video_do_ioctl(struct inode *inode, struct file *file, int *on = arg; if (*on) { + if (saa7134_no_overlay > 0) { + printk ("no_overlay\n"); + return -EINVAL; + } + if (!res_get(dev,fh,RESOURCE_OVERLAY)) return -EBUSY; spin_lock_irqsave(&dev->slock,flags); @@ -2282,7 +2304,7 @@ static struct file_operations radio_fops = struct video_device saa7134_video_template = { .name = "saa7134-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_OVERLAY| + .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER| VID_TYPE_CLIPPING|VID_TYPE_SCALES, .hardware = 0, .fops = &video_fops, diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h index 3261d8bebdd..17ba34f3076 100644 --- a/drivers/media/video/saa7134/saa7134.h +++ b/drivers/media/video/saa7134/saa7134.h @@ -29,6 +29,7 @@ #include <linux/input.h> #include <linux/notifier.h> #include <linux/delay.h> +#include <linux/mutex.h> #include <asm/io.h> @@ -60,6 +61,7 @@ enum saa7134_tvaudio_mode { TVAUDIO_FM_K_STEREO = 4, TVAUDIO_NICAM_AM = 5, TVAUDIO_NICAM_FM = 6, + TVAUDIO_AM_MONO = 7 }; enum saa7134_audio_in { @@ -210,6 +212,15 @@ struct saa7134_format { #define SAA7134_BOARD_MSI_TVATANYWHERE_PLUS 82 #define SAA7134_BOARD_CINERGY250PCI 83 #define SAA7134_BOARD_FLYDVB_TRIO 84 +#define SAA7134_BOARD_AVERMEDIA_777 85 +#define SAA7134_BOARD_FLYDVBT_LR301 86 +#define SAA7134_BOARD_ADS_DUO_CARDBUS_PTV331 87 +#define SAA7134_BOARD_TEVION_DVBT_220RF 88 +#define SAA7134_BOARD_ELSA_700TV 89 +#define SAA7134_BOARD_KWORLD_ATSC110 90 +#define SAA7134_BOARD_AVERMEDIA_A169_B 91 +#define SAA7134_BOARD_AVERMEDIA_A169_B1 92 +#define SAA7134_BOARD_MD7134_BRIDGE_2 93 #define SAA7134_MAXBOARDS 8 #define SAA7134_INPUT_MAX 8 @@ -359,7 +370,7 @@ struct saa7134_fh { /* dmasound dsp status */ struct saa7134_dmasound { - struct semaphore lock; + struct mutex lock; int minor_mixer; int minor_dsp; unsigned int users_dsp; @@ -423,7 +434,7 @@ struct saa7134_mpeg_ops { /* global device status */ struct saa7134_dev { struct list_head devlist; - struct semaphore lock; + struct mutex lock; spinlock_t slock; #ifdef VIDIOC_G_PRIORITY struct v4l2_prio_state prio; @@ -546,6 +557,7 @@ struct saa7134_dev { /* saa7134-core.c */ extern struct list_head saa7134_devlist; +extern int saa7134_no_overlay; void saa7134_track_gpio(struct saa7134_dev *dev, char *msg); diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c index a796a4e1917..027c8a074df 100644 --- a/drivers/media/video/tda8290.c +++ b/drivers/media/video/tda8290.c @@ -281,7 +281,7 @@ static void tda827xa_agcf(struct i2c_client *c) static void tda8290_i2c_bridge(struct i2c_client *c, int close) { unsigned char enable[2] = { 0x21, 0xC0 }; - unsigned char disable[2] = { 0x21, 0x80 }; + unsigned char disable[2] = { 0x21, 0x00 }; unsigned char *msg; if(close) { msg = enable; @@ -302,6 +302,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) unsigned char soft_reset[] = { 0x00, 0x00 }; unsigned char easy_mode[] = { 0x01, t->tda8290_easy_mode }; unsigned char expert_mode[] = { 0x01, 0x80 }; + unsigned char agc_out_on[] = { 0x02, 0x00 }; unsigned char gainset_off[] = { 0x28, 0x14 }; unsigned char if_agc_spd[] = { 0x0f, 0x88 }; unsigned char adc_head_6[] = { 0x05, 0x04 }; @@ -320,6 +321,7 @@ static int tda8290_tune(struct i2c_client *c, u16 ifc, unsigned int freq) pll_stat; i2c_master_send(c, easy_mode, 2); + i2c_master_send(c, agc_out_on, 2); i2c_master_send(c, soft_reset, 2); msleep(1); @@ -470,6 +472,7 @@ static void standby(struct i2c_client *c) struct tuner *t = i2c_get_clientdata(c); unsigned char cb1[] = { 0x30, 0xD0 }; unsigned char tda8290_standby[] = { 0x00, 0x02 }; + unsigned char tda8290_agc_tri[] = { 0x02, 0x20 }; struct i2c_msg msg = {.addr = t->tda827x_addr, .flags=0, .buf=cb1, .len = 2}; tda8290_i2c_bridge(c, 1); @@ -477,6 +480,7 @@ static void standby(struct i2c_client *c) cb1[1] = 0x90; i2c_transfer(c->adapter, &msg, 1); tda8290_i2c_bridge(c, 0); + i2c_master_send(c, tda8290_agc_tri, 2); i2c_master_send(c, tda8290_standby, 2); } @@ -565,7 +569,7 @@ int tda8290_init(struct i2c_client *c) strlcpy(c->name, "tda8290+75a", sizeof(c->name)); t->tda827x_ver = 2; } - tuner_info("tuner: type set to %s\n", c->name); + tuner_info("type set to %s\n", c->name); t->set_tv_freq = set_tv_freq; t->set_radio_freq = set_radio_freq; diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c index ed4c04119cc..0243700f58a 100644 --- a/drivers/media/video/tda9840.c +++ b/drivers/media/video/tda9840.c @@ -24,6 +24,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/module.h> #include <linux/ioctl.h> #include <linux/i2c.h> @@ -222,7 +223,7 @@ static int detach(struct i2c_client *client) static struct i2c_driver driver = { .driver = { - .name = "tda9840", + .name = "tda9840", }, .id = I2C_DRIVERID_TDA9840, .attach_adapter = attach, diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c index bb35844e384..774ed0dbc56 100644 --- a/drivers/media/video/tea6415c.c +++ b/drivers/media/video/tea6415c.c @@ -26,6 +26,7 @@ Foundation, Inc., 675 Mvss Ave, Cambridge, MA 02139, USA. */ + #include <linux/module.h> #include <linux/ioctl.h> #include <linux/i2c.h> @@ -107,7 +108,7 @@ static int switch_matrix(struct i2c_client *client, int i, int o) { u8 byte = 0; int ret; - + dprintk("adr:0x%02x, i:%d, o:%d\n", client->addr, i, o); /* check if the pins are valid */ @@ -191,7 +192,7 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg) static struct i2c_driver driver = { .driver = { - .name = "tea6415c", + .name = "tea6415c", }, .id = I2C_DRIVERID_TEA6415C, .attach_adapter = attach, diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c index 4dcba5a4fff..ad7d2872cfb 100644 --- a/drivers/media/video/tea6420.c +++ b/drivers/media/video/tea6420.c @@ -26,6 +26,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #include <linux/module.h> #include <linux/ioctl.h> #include <linux/i2c.h> @@ -83,7 +84,7 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g) dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret); return -EIO; } - + return 0; } @@ -167,7 +168,7 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg) static struct i2c_driver driver = { .driver = { - .name = "tea6420", + .name = "tea6420", }, .id = I2C_DRIVERID_TEA6420, .attach_adapter = attach, diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c index b6101bf446d..32e1849441f 100644 --- a/drivers/media/video/tuner-core.c +++ b/drivers/media/video/tuner-core.c @@ -173,7 +173,6 @@ static void set_type(struct i2c_client *c, unsigned int type, } t->type = type; - switch (t->type) { case TUNER_MT2032: microtune_init(c); @@ -404,15 +403,16 @@ static void tuner_status(struct i2c_client *client) tuner_info("Tuner mode: %s\n", p); tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); tuner_info("Standard: 0x%08llx\n", t->std); - if (t->mode == V4L2_TUNER_RADIO) { - if (t->has_signal) { - tuner_info("Signal strength: %d\n", t->has_signal(client)); - } - if (t->is_stereo) { - tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no"); - } + if (t->mode != V4L2_TUNER_RADIO) + return; + if (t->has_signal) { + tuner_info("Signal strength: %d\n", t->has_signal(client)); + } + if (t->is_stereo) { + tuner_info("Stereo: %s\n", t->is_stereo(client) ? "yes" : "no"); } } + /* ---------------------------------------------------------------------- */ /* static var Used only in tuner_attach and tuner_probe */ @@ -744,33 +744,29 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; switch_v4l2(); - if (V4L2_TUNER_RADIO == t->mode) { - - if (t->has_signal) - tuner->signal = t->has_signal(client); - - if (t->is_stereo) { - if (t->is_stereo(client)) { - tuner->rxsubchans = - V4L2_TUNER_SUB_STEREO | - V4L2_TUNER_SUB_MONO; - } else { - tuner->rxsubchans = - V4L2_TUNER_SUB_MONO; - } - } - - tuner->capability |= - V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; - - tuner->audmode = t->audmode; - - tuner->rangelow = radio_range[0] * 16000; - tuner->rangehigh = radio_range[1] * 16000; - } else { + tuner->type = t->mode; + if (t->mode != V4L2_TUNER_RADIO) { tuner->rangelow = tv_range[0] * 16; tuner->rangehigh = tv_range[1] * 16; + break; } + + /* radio mode */ + if (t->has_signal) + tuner->signal = t->has_signal(client); + + tuner->rxsubchans = + V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + if (t->is_stereo) { + tuner->rxsubchans = t->is_stereo(client) ? + V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO; + } + + tuner->capability |= + V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; + tuner->audmode = t->audmode; + tuner->rangelow = radio_range[0] * 16000; + tuner->rangehigh = radio_range[1] * 16000; break; } case VIDIOC_S_TUNER: @@ -782,10 +778,11 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) switch_v4l2(); - if (V4L2_TUNER_RADIO == t->mode) { - t->audmode = tuner->audmode; - set_radio_freq(client, t->radio_freq); - } + /* do nothing unless we're a radio tuner */ + if (t->mode != V4L2_TUNER_RADIO) + break; + t->audmode = tuner->audmode; + set_radio_freq(client, t->radio_freq); break; } case VIDIOC_LOG_STATUS: diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c index 37977ff4978..5d7abed7167 100644 --- a/drivers/media/video/tuner-simple.c +++ b/drivers/media/video/tuner-simple.c @@ -79,17 +79,6 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner"); #define TUNER_PLL_LOCKED 0x40 #define TUNER_STEREO_MK3 0x04 -#define TUNER_PARAM_ANALOG 0 /* to be removed */ -/* FIXME: - * Right now, all tuners are using the first tuner_params[] array element - * for analog mode. In the future, we will be merging similar tuner - * definitions together, such that each tuner definition will have a - * tuner_params struct for each available video standard. At that point, - * TUNER_PARAM_ANALOG will be removed, and the tuner_params[] array - * element will be chosen based on the video standard in use. - * - */ - /* ---------------------------------------------------------------------- */ static int tuner_getstatus(struct i2c_client *c) @@ -133,14 +122,53 @@ static int tuner_stereo(struct i2c_client *c) static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) { struct tuner *t = i2c_get_clientdata(c); - u8 config, tuneraddr; + u8 config, cb, tuneraddr; u16 div; struct tunertype *tun; u8 buffer[4]; int rc, IFPCoff, i, j; + enum param_type desired_type; tun = &tuners[t->type]; - j = TUNER_PARAM_ANALOG; + + /* IFPCoff = Video Intermediate Frequency - Vif: + 940 =16*58.75 NTSC/J (Japan) + 732 =16*45.75 M/N STD + 704 =16*44 ATSC (at DVB code) + 632 =16*39.50 I U.K. + 622.4=16*38.90 B/G D/K I, L STD + 592 =16*37.00 D China + 590 =16.36.875 B Australia + 543.2=16*33.95 L' STD + 171.2=16*10.70 FM Radio (at set_radio_freq) + */ + + if (t->std == V4L2_STD_NTSC_M_JP) { + IFPCoff = 940; + desired_type = TUNER_PARAM_TYPE_NTSC; + } else if ((t->std & V4L2_STD_MN) && + !(t->std & ~V4L2_STD_MN)) { + IFPCoff = 732; + desired_type = TUNER_PARAM_TYPE_NTSC; + } else if (t->std == V4L2_STD_SECAM_LC) { + IFPCoff = 543; + desired_type = TUNER_PARAM_TYPE_SECAM; + } else { + IFPCoff = 623; + desired_type = TUNER_PARAM_TYPE_PAL; + } + + for (j = 0; j < tun->count-1; j++) { + if (desired_type != tun->params[j].type) + continue; + break; + } + /* use default tuner_params if desired_type not available */ + if (desired_type != tun->params[j].type) { + tuner_dbg("IFPCoff = %d: tuner_params undefined for tuner %d\n", + IFPCoff,t->type); + j = 0; + } for (i = 0; i < tun->params[j].count; i++) { if (freq > tun->params[j].ranges[i].limit) @@ -152,11 +180,20 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) freq, tun->params[j].ranges[i - 1].limit); freq = tun->params[j].ranges[--i].limit; } - config = tun->params[j].ranges[i].cb; - /* i == 0 -> VHF_LO */ - /* i == 1 -> VHF_HI */ - /* i == 2 -> UHF */ - tuner_dbg("tv: range %d\n",i); + config = tun->params[j].ranges[i].config; + cb = tun->params[j].ranges[i].cb; + /* i == 0 -> VHF_LO + * i == 1 -> VHF_HI + * i == 2 -> UHF */ + tuner_dbg("tv: param %d, range %d\n",j,i); + + div=freq + IFPCoff + offset; + + tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n", + freq / 16, freq % 16 * 100 / 16, + IFPCoff / 16, IFPCoff % 16 * 100 / 16, + offset / 16, offset % 16 * 100 / 16, + div); /* tv norm specific stuff for multi-norm tuners */ switch (t->type) { @@ -164,40 +201,40 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) /* 0x01 -> ??? no change ??? */ /* 0x02 -> PAL BDGHI / SECAM L */ /* 0x04 -> ??? PAL others / SECAM others ??? */ - config &= ~0x02; + cb &= ~0x02; if (t->std & V4L2_STD_SECAM) - config |= 0x02; + cb |= 0x02; break; case TUNER_TEMIC_4046FM5: - config &= ~0x0f; + cb &= ~0x0f; if (t->std & V4L2_STD_PAL_BG) { - config |= TEMIC_SET_PAL_BG; + cb |= TEMIC_SET_PAL_BG; } else if (t->std & V4L2_STD_PAL_I) { - config |= TEMIC_SET_PAL_I; + cb |= TEMIC_SET_PAL_I; } else if (t->std & V4L2_STD_PAL_DK) { - config |= TEMIC_SET_PAL_DK; + cb |= TEMIC_SET_PAL_DK; } else if (t->std & V4L2_STD_SECAM_L) { - config |= TEMIC_SET_PAL_L; + cb |= TEMIC_SET_PAL_L; } break; case TUNER_PHILIPS_FQ1216ME: - config &= ~0x0f; + cb &= ~0x0f; if (t->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) { - config |= PHILIPS_SET_PAL_BGDK; + cb |= PHILIPS_SET_PAL_BGDK; } else if (t->std & V4L2_STD_PAL_I) { - config |= PHILIPS_SET_PAL_I; + cb |= PHILIPS_SET_PAL_I; } else if (t->std & V4L2_STD_SECAM_L) { - config |= PHILIPS_SET_PAL_L; + cb |= PHILIPS_SET_PAL_L; } break; @@ -207,15 +244,15 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) /* 0x01 -> ATSC antenna input 2 */ /* 0x02 -> NTSC antenna input 1 */ /* 0x03 -> NTSC antenna input 2 */ - config &= ~0x03; + cb &= ~0x03; if (!(t->std & V4L2_STD_ATSC)) - config |= 2; + cb |= 2; /* FIXME: input */ break; case TUNER_MICROTUNE_4042FI5: /* Set the charge pump for fast tuning */ - tun->params[j].config |= TUNER_CHARGE_PUMP; + config |= TUNER_CHARGE_PUMP; break; case TUNER_PHILIPS_TUV1236D: @@ -227,9 +264,9 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) buffer[1] = 0x00; buffer[2] = 0x17; buffer[3] = 0x00; - config &= ~0x40; + cb &= ~0x40; if (t->std & V4L2_STD_ATSC) { - config |= 0x40; + cb |= 0x40; buffer[1] = 0x04; } /* set to the correct mode (analog or digital) */ @@ -244,47 +281,16 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) break; } - /* IFPCoff = Video Intermediate Frequency - Vif: - 940 =16*58.75 NTSC/J (Japan) - 732 =16*45.75 M/N STD - 704 =16*44 ATSC (at DVB code) - 632 =16*39.50 I U.K. - 622.4=16*38.90 B/G D/K I, L STD - 592 =16*37.00 D China - 590 =16.36.875 B Australia - 543.2=16*33.95 L' STD - 171.2=16*10.70 FM Radio (at set_radio_freq) - */ - - if (t->std == V4L2_STD_NTSC_M_JP) { - IFPCoff = 940; - } else if ((t->std & V4L2_STD_MN) && - !(t->std & ~V4L2_STD_MN)) { - IFPCoff = 732; - } else if (t->std == V4L2_STD_SECAM_LC) { - IFPCoff = 543; - } else { - IFPCoff = 623; - } - - div=freq + IFPCoff + offset; - - tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n", - freq / 16, freq % 16 * 100 / 16, - IFPCoff / 16, IFPCoff % 16 * 100 / 16, - offset / 16, offset % 16 * 100 / 16, - div); - if (tuners[t->type].params->cb_first_if_lower_freq && div < t->last_div) { - buffer[0] = tun->params[j].config; - buffer[1] = config; + buffer[0] = config; + buffer[1] = cb; buffer[2] = (div>>8) & 0x7f; buffer[3] = div & 0xff; } else { buffer[0] = (div>>8) & 0x7f; buffer[1] = div & 0xff; - buffer[2] = tun->params[j].config; - buffer[3] = config; + buffer[2] = config; + buffer[3] = cb; } t->last_div = div; tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", @@ -312,11 +318,11 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq) } /* Set the charge pump for optimized phase noise figure */ - tun->params[j].config &= ~TUNER_CHARGE_PUMP; + config &= ~TUNER_CHARGE_PUMP; buffer[0] = (div>>8) & 0x7f; buffer[1] = div & 0xff; - buffer[2] = tun->params[j].config; - buffer[3] = config; + buffer[2] = config; + buffer[3] = cb; tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n", buffer[0],buffer[1],buffer[2],buffer[3]); @@ -332,12 +338,21 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) u8 buffer[4]; u16 div; int rc, j; + enum param_type desired_type = TUNER_PARAM_TYPE_RADIO; tun = &tuners[t->type]; - j = TUNER_PARAM_ANALOG; + + for (j = 0; j < tun->count-1; j++) { + if (desired_type != tun->params[j].type) + continue; + break; + } + /* use default tuner_params if desired_type not available */ + if (desired_type != tun->params[j].type) + j = 0; div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */ - buffer[2] = (tun->params[j].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ + buffer[2] = (tun->params[j].ranges[0].config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */ switch (t->type) { case TUNER_TENA_9533_DI: @@ -349,6 +364,9 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq) case TUNER_PHILIPS_FMD1216ME_MK3: buffer[3] = 0x19; break; + case TUNER_TNF_5335MF: + buffer[3] = 0x11; + break; case TUNER_PHILIPS_FM1256_IH3: div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */ buffer[3] = 0x19; diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c index 6fe781798d8..72e0f01db56 100644 --- a/drivers/media/video/tuner-types.c +++ b/drivers/media/video/tuner-types.c @@ -23,22 +23,25 @@ * Each tuner_params array may contain one or more elements, one * for each video standard. * - * FIXME: Some tuner_range definitions are duplicated, and - * should be eliminated. + * FIXME: tuner_params struct contains an element, tda988x. We must + * set this for all tuners that contain a tda988x chip, and then we + * can remove this setting from the various card structs. * - * FIXME: tunertype struct contains an element, has_tda988x. - * We must set this for all tunertypes that contain a tda988x - * chip, and then we can remove this setting from the various - * card structs. + * FIXME: Right now, all tuners are using the first tuner_params[] + * array element for analog mode. In the future, we will be merging + * similar tuner definitions together, such that each tuner definition + * will have a tuner_params struct for each available video standard. + * At that point, the tuner_params[] array element will be chosen + * based on the video standard in use. */ /* 0-9 */ /* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */ static struct tuner_range tuner_temic_pal_ranges[] = { - { 16 * 140.25 /*MHz*/, 0x02, }, - { 16 * 463.25 /*MHz*/, 0x04, }, - { 16 * 999.99 , 0x01, }, + { 16 * 140.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, + { 16 * 999.99 , 0x8e, 0x01, }, }; static struct tuner_params tuner_temic_pal_params[] = { @@ -46,16 +49,15 @@ static struct tuner_params tuner_temic_pal_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_temic_pal_ranges, .count = ARRAY_SIZE(tuner_temic_pal_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_PHILIPS_PAL_I - Philips PAL_I ------------ */ static struct tuner_range tuner_philips_pal_i_ranges[] = { - { 16 * 140.25 /*MHz*/, 0xa0, }, - { 16 * 463.25 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 140.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_philips_pal_i_params[] = { @@ -63,16 +65,15 @@ static struct tuner_params tuner_philips_pal_i_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_philips_pal_i_ranges, .count = ARRAY_SIZE(tuner_philips_pal_i_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_PHILIPS_NTSC - Philips NTSC ------------ */ static struct tuner_range tuner_philips_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0xa0, }, - { 16 * 451.25 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 451.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_philips_ntsc_params[] = { @@ -80,7 +81,6 @@ static struct tuner_params tuner_philips_ntsc_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_philips_ntsc_ranges, .count = ARRAY_SIZE(tuner_philips_ntsc_ranges), - .config = 0x8e, .cb_first_if_lower_freq = 1, }, }; @@ -88,9 +88,9 @@ static struct tuner_params tuner_philips_ntsc_params[] = { /* ------------ TUNER_PHILIPS_SECAM - Philips SECAM ------------ */ static struct tuner_range tuner_philips_secam_ranges[] = { - { 16 * 168.25 /*MHz*/, 0xa7, }, - { 16 * 447.25 /*MHz*/, 0x97, }, - { 16 * 999.99 , 0x37, }, + { 16 * 168.25 /*MHz*/, 0x8e, 0xa7, }, + { 16 * 447.25 /*MHz*/, 0x8e, 0x97, }, + { 16 * 999.99 , 0x8e, 0x37, }, }; static struct tuner_params tuner_philips_secam_params[] = { @@ -98,7 +98,6 @@ static struct tuner_params tuner_philips_secam_params[] = { .type = TUNER_PARAM_TYPE_SECAM, .ranges = tuner_philips_secam_ranges, .count = ARRAY_SIZE(tuner_philips_secam_ranges), - .config = 0x8e, .cb_first_if_lower_freq = 1, }, }; @@ -106,9 +105,9 @@ static struct tuner_params tuner_philips_secam_params[] = { /* ------------ TUNER_PHILIPS_PAL - Philips PAL ------------ */ static struct tuner_range tuner_philips_pal_ranges[] = { - { 16 * 168.25 /*MHz*/, 0xa0, }, - { 16 * 447.25 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 447.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_philips_pal_params[] = { @@ -116,7 +115,6 @@ static struct tuner_params tuner_philips_pal_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_philips_pal_ranges, .count = ARRAY_SIZE(tuner_philips_pal_ranges), - .config = 0x8e, .cb_first_if_lower_freq = 1, }, }; @@ -124,9 +122,9 @@ static struct tuner_params tuner_philips_pal_params[] = { /* ------------ TUNER_TEMIC_NTSC - TEMIC NTSC ------------ */ static struct tuner_range tuner_temic_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x02, }, - { 16 * 463.25 /*MHz*/, 0x04, }, - { 16 * 999.99 , 0x01, }, + { 16 * 157.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x04, }, + { 16 * 999.99 , 0x8e, 0x01, }, }; static struct tuner_params tuner_temic_ntsc_params[] = { @@ -134,16 +132,15 @@ static struct tuner_params tuner_temic_ntsc_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_temic_ntsc_ranges, .count = ARRAY_SIZE(tuner_temic_ntsc_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_TEMIC_PAL_I - TEMIC PAL_I ------------ */ static struct tuner_range tuner_temic_pal_i_ranges[] = { - { 16 * 170.00 /*MHz*/, 0x02, }, - { 16 * 450.00 /*MHz*/, 0x04, }, - { 16 * 999.99 , 0x01, }, + { 16 * 170.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 450.00 /*MHz*/, 0x8e, 0x04, }, + { 16 * 999.99 , 0x8e, 0x01, }, }; static struct tuner_params tuner_temic_pal_i_params[] = { @@ -151,16 +148,15 @@ static struct tuner_params tuner_temic_pal_i_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_temic_pal_i_ranges, .count = ARRAY_SIZE(tuner_temic_pal_i_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_TEMIC_4036FY5_NTSC - TEMIC NTSC ------------ */ static struct tuner_range tuner_temic_4036fy5_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0xa0, }, - { 16 * 463.25 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = { @@ -168,16 +164,15 @@ static struct tuner_params tuner_temic_4036fy5_ntsc_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_temic_4036fy5_ntsc_ranges, .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_ALPS_TSBH1_NTSC - TEMIC NTSC ------------ */ static struct tuner_range tuner_alps_tsb_1_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x01, }, - { 16 * 385.25 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x08, }, + { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 385.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, }; static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = { @@ -185,7 +180,6 @@ static struct tuner_params tuner_alps_tsbh1_ntsc_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_alps_tsb_1_ranges, .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), - .config = 0x8e, }, }; @@ -197,16 +191,15 @@ static struct tuner_params tuner_alps_tsb_1_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_alps_tsb_1_ranges, .count = ARRAY_SIZE(tuner_alps_tsb_1_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_ALPS_TSBB5_PAL_I - Alps PAL_I ------------ */ static struct tuner_range tuner_alps_tsb_5_pal_ranges[] = { - { 16 * 133.25 /*MHz*/, 0x01, }, - { 16 * 351.25 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x08, }, + { 16 * 133.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 351.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, }; static struct tuner_params tuner_alps_tsbb5_params[] = { @@ -214,7 +207,6 @@ static struct tuner_params tuner_alps_tsbb5_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_alps_tsb_5_pal_ranges, .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), - .config = 0x8e, }, }; @@ -225,7 +217,6 @@ static struct tuner_params tuner_alps_tsbe5_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_alps_tsb_5_pal_ranges, .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), - .config = 0x8e, }, }; @@ -236,33 +227,31 @@ static struct tuner_params tuner_alps_tsbc5_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_alps_tsb_5_pal_ranges, .count = ARRAY_SIZE(tuner_alps_tsb_5_pal_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_TEMIC_4006FH5_PAL - TEMIC PAL ------------ */ -static struct tuner_range tuner_temic_4006fh5_pal_ranges[] = { - { 16 * 170.00 /*MHz*/, 0xa0, }, - { 16 * 450.00 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, +static struct tuner_range tuner_lg_pal_ranges[] = { + { 16 * 170.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 450.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_temic_4006fh5_params[] = { { .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_4006fh5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_4006fh5_pal_ranges), - .config = 0x8e, + .ranges = tuner_lg_pal_ranges, + .count = ARRAY_SIZE(tuner_lg_pal_ranges), }, }; /* ------------ TUNER_ALPS_TSHC6_NTSC - Alps NTSC ------------ */ static struct tuner_range tuner_alps_tshc6_ntsc_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x14, }, - { 16 * 385.25 /*MHz*/, 0x12, }, - { 16 * 999.99 , 0x11, }, + { 16 * 137.25 /*MHz*/, 0x8e, 0x14, }, + { 16 * 385.25 /*MHz*/, 0x8e, 0x12, }, + { 16 * 999.99 , 0x8e, 0x11, }, }; static struct tuner_params tuner_alps_tshc6_params[] = { @@ -270,16 +259,15 @@ static struct tuner_params tuner_alps_tshc6_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_alps_tshc6_ntsc_ranges, .count = ARRAY_SIZE(tuner_alps_tshc6_ntsc_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_TEMIC_PAL_DK - TEMIC PAL ------------ */ static struct tuner_range tuner_temic_pal_dk_ranges[] = { - { 16 * 168.25 /*MHz*/, 0xa0, }, - { 16 * 456.25 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 168.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 456.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_temic_pal_dk_params[] = { @@ -287,16 +275,15 @@ static struct tuner_params tuner_temic_pal_dk_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_temic_pal_dk_ranges, .count = ARRAY_SIZE(tuner_temic_pal_dk_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_PHILIPS_NTSC_M - Philips NTSC ------------ */ static struct tuner_range tuner_philips_ntsc_m_ranges[] = { - { 16 * 160.00 /*MHz*/, 0xa0, }, - { 16 * 454.00 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 160.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_philips_ntsc_m_params[] = { @@ -304,16 +291,15 @@ static struct tuner_params tuner_philips_ntsc_m_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_philips_ntsc_m_ranges, .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_TEMIC_4066FY5_PAL_I - TEMIC PAL_I ------------ */ static struct tuner_range tuner_temic_40x6f_5_pal_ranges[] = { - { 16 * 169.00 /*MHz*/, 0xa0, }, - { 16 * 454.00 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 169.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = { @@ -321,7 +307,6 @@ static struct tuner_params tuner_temic_4066fy5_pal_i_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_temic_40x6f_5_pal_ranges, .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), - .config = 0x8e, }, }; @@ -332,7 +317,6 @@ static struct tuner_params tuner_temic_4006fn5_multi_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_temic_40x6f_5_pal_ranges, .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), - .config = 0x8e, }, }; @@ -340,9 +324,9 @@ static struct tuner_params tuner_temic_4006fn5_multi_params[] = { /* ------------ TUNER_TEMIC_4009FR5_PAL - TEMIC PAL ------------ */ static struct tuner_range tuner_temic_4009f_5_pal_ranges[] = { - { 16 * 141.00 /*MHz*/, 0xa0, }, - { 16 * 464.00 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 141.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 464.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_temic_4009f_5_params[] = { @@ -350,58 +334,42 @@ static struct tuner_params tuner_temic_4009f_5_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_temic_4009f_5_pal_ranges, .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_TEMIC_4039FR5_NTSC - TEMIC NTSC ------------ */ -static struct tuner_range tuner_temic_4039fr5_ntsc_ranges[] = { - { 16 * 158.00 /*MHz*/, 0xa0, }, - { 16 * 453.00 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, +static struct tuner_range tuner_temic_4x3x_f_5_ntsc_ranges[] = { + { 16 * 158.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 453.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_temic_4039fr5_params[] = { { .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_temic_4039fr5_ntsc_ranges, - .count = ARRAY_SIZE(tuner_temic_4039fr5_ntsc_ranges), - .config = 0x8e, + .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, + .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), }, }; /* ------------ TUNER_TEMIC_4046FM5 - TEMIC PAL ------------ */ -static struct tuner_range tuner_temic_4046fm5_pal_ranges[] = { - { 16 * 169.00 /*MHz*/, 0xa0, }, - { 16 * 454.00 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, -}; - static struct tuner_params tuner_temic_4046fm5_params[] = { { .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_4046fm5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_4046fm5_pal_ranges), - .config = 0x8e, + .ranges = tuner_temic_40x6f_5_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_40x6f_5_pal_ranges), }, }; /* ------------ TUNER_PHILIPS_PAL_DK - Philips PAL ------------ */ -static struct tuner_range tuner_lg_pal_ranges[] = { - { 16 * 170.00 /*MHz*/, 0xa0, }, - { 16 * 450.00 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, -}; - static struct tuner_params tuner_philips_pal_dk_params[] = { { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_lg_pal_ranges, .count = ARRAY_SIZE(tuner_lg_pal_ranges), - .config = 0x8e, }, }; @@ -412,7 +380,6 @@ static struct tuner_params tuner_philips_fq1216me_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_lg_pal_ranges, .count = ARRAY_SIZE(tuner_lg_pal_ranges), - .config = 0x8e, }, }; @@ -423,7 +390,6 @@ static struct tuner_params tuner_lg_pal_i_fm_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_lg_pal_ranges, .count = ARRAY_SIZE(tuner_lg_pal_ranges), - .config = 0x8e, }, }; @@ -434,16 +400,15 @@ static struct tuner_params tuner_lg_pal_i_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_lg_pal_ranges, .count = ARRAY_SIZE(tuner_lg_pal_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_LG_NTSC_FM - LGINNOTEK NTSC ------------ */ static struct tuner_range tuner_lg_ntsc_fm_ranges[] = { - { 16 * 210.00 /*MHz*/, 0xa0, }, - { 16 * 497.00 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 210.00 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 497.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_lg_ntsc_fm_params[] = { @@ -451,7 +416,6 @@ static struct tuner_params tuner_lg_ntsc_fm_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_lg_ntsc_fm_ranges, .count = ARRAY_SIZE(tuner_lg_ntsc_fm_ranges), - .config = 0x8e, }, }; @@ -462,7 +426,6 @@ static struct tuner_params tuner_lg_pal_fm_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_lg_pal_ranges, .count = ARRAY_SIZE(tuner_lg_pal_ranges), - .config = 0x8e, }, }; @@ -473,7 +436,6 @@ static struct tuner_params tuner_lg_pal_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_lg_pal_ranges, .count = ARRAY_SIZE(tuner_lg_pal_ranges), - .config = 0x8e, }, }; @@ -485,16 +447,15 @@ static struct tuner_params tuner_temic_4009_fn5_multi_pal_fm_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_temic_4009f_5_pal_ranges, .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_SHARP_2U5JF5540_NTSC - SHARP NTSC ------------ */ static struct tuner_range tuner_sharp_2u5jf5540_ntsc_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x01, }, - { 16 * 317.25 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x08, }, + { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 317.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, }; static struct tuner_params tuner_sharp_2u5jf5540_params[] = { @@ -502,16 +463,15 @@ static struct tuner_params tuner_sharp_2u5jf5540_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_sharp_2u5jf5540_ntsc_ranges, .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_ntsc_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_Samsung_PAL_TCPM9091PD27 - Samsung PAL ------------ */ static struct tuner_range tuner_samsung_pal_tcpm9091pd27_ranges[] = { - { 16 * 169 /*MHz*/, 0xa0, }, - { 16 * 464 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 169 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 464 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = { @@ -519,7 +479,6 @@ static struct tuner_params tuner_samsung_pal_tcpm9091pd27_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_samsung_pal_tcpm9091pd27_ranges, .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_ranges), - .config = 0x8e, }, }; @@ -530,50 +489,35 @@ static struct tuner_params tuner_temic_4106fh5_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_temic_4009f_5_pal_ranges, .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_TEMIC_4012FY5 - TEMIC PAL ------------ */ -static struct tuner_range tuner_temic_4012fy5_pal_ranges[] = { - { 16 * 140.25 /*MHz*/, 0x02, }, - { 16 * 463.25 /*MHz*/, 0x04, }, - { 16 * 999.99 , 0x01, }, -}; - static struct tuner_params tuner_temic_4012fy5_params[] = { { .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_temic_4012fy5_pal_ranges, - .count = ARRAY_SIZE(tuner_temic_4012fy5_pal_ranges), - .config = 0x8e, + .ranges = tuner_temic_pal_ranges, + .count = ARRAY_SIZE(tuner_temic_pal_ranges), }, }; /* ------------ TUNER_TEMIC_4136FY5 - TEMIC NTSC ------------ */ -static struct tuner_range tuner_temic_4136_fy5_ntsc_ranges[] = { - { 16 * 158.00 /*MHz*/, 0xa0, }, - { 16 * 453.00 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, -}; - static struct tuner_params tuner_temic_4136_fy5_params[] = { { .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_temic_4136_fy5_ntsc_ranges, - .count = ARRAY_SIZE(tuner_temic_4136_fy5_ntsc_ranges), - .config = 0x8e, + .ranges = tuner_temic_4x3x_f_5_ntsc_ranges, + .count = ARRAY_SIZE(tuner_temic_4x3x_f_5_ntsc_ranges), }, }; /* ------------ TUNER_LG_PAL_NEW_TAPC - LGINNOTEK PAL ------------ */ static struct tuner_range tuner_lg_new_tapc_ranges[] = { - { 16 * 170.00 /*MHz*/, 0x01, }, - { 16 * 450.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x08, }, + { 16 * 170.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 450.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, }; static struct tuner_params tuner_lg_pal_new_tapc_params[] = { @@ -581,16 +525,15 @@ static struct tuner_params tuner_lg_pal_new_tapc_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_lg_new_tapc_ranges, .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_PHILIPS_FM1216ME_MK3 - Philips PAL ------------ */ static struct tuner_range tuner_fm1216me_mk3_pal_ranges[] = { - { 16 * 158.00 /*MHz*/, 0x01, }, - { 16 * 442.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x04, }, + { 16 * 158.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, }; static struct tuner_params tuner_fm1216me_mk3_params[] = { @@ -598,7 +541,6 @@ static struct tuner_params tuner_fm1216me_mk3_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_fm1216me_mk3_pal_ranges, .count = ARRAY_SIZE(tuner_fm1216me_mk3_pal_ranges), - .config = 0x8e, .cb_first_if_lower_freq = 1, }, }; @@ -610,7 +552,6 @@ static struct tuner_params tuner_lg_ntsc_new_tapc_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_lg_new_tapc_ranges, .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), - .config = 0x8e, }, }; @@ -622,16 +563,15 @@ static struct tuner_params tuner_hitachi_ntsc_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_lg_new_tapc_ranges, .count = ARRAY_SIZE(tuner_lg_new_tapc_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_PHILIPS_PAL_MK - Philips PAL ------------ */ static struct tuner_range tuner_philips_pal_mk_pal_ranges[] = { - { 16 * 140.25 /*MHz*/, 0x01, }, - { 16 * 463.25 /*MHz*/, 0xc2, }, - { 16 * 999.99 , 0xcf, }, + { 16 * 140.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0xc2, }, + { 16 * 999.99 , 0x8e, 0xcf, }, }; static struct tuner_params tuner_philips_pal_mk_params[] = { @@ -639,16 +579,15 @@ static struct tuner_params tuner_philips_pal_mk_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_philips_pal_mk_pal_ranges, .count = ARRAY_SIZE(tuner_philips_pal_mk_pal_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_PHILIPS_ATSC - Philips ATSC ------------ */ static struct tuner_range tuner_philips_atsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0xa0, }, - { 16 * 454.00 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_philips_atsc_params[] = { @@ -656,16 +595,15 @@ static struct tuner_params tuner_philips_atsc_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_philips_atsc_ranges, .count = ARRAY_SIZE(tuner_philips_atsc_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_PHILIPS_FM1236_MK3 - Philips NTSC ------------ */ static struct tuner_range tuner_fm1236_mk3_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x01, }, - { 16 * 442.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x04, }, + { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 442.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, }; static struct tuner_params tuner_fm1236_mk3_params[] = { @@ -673,25 +611,17 @@ static struct tuner_params tuner_fm1236_mk3_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_fm1236_mk3_ntsc_ranges, .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), - .config = 0x8e, .cb_first_if_lower_freq = 1, }, }; /* ------------ TUNER_PHILIPS_4IN1 - Philips NTSC ------------ */ -static struct tuner_range tuner_philips_4in1_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x01, }, - { 16 * 442.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x04, }, -}; - static struct tuner_params tuner_philips_4in1_params[] = { { .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_4in1_ntsc_ranges, - .count = ARRAY_SIZE(tuner_philips_4in1_ntsc_ranges), - .config = 0x8e, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), }, }; @@ -702,16 +632,15 @@ static struct tuner_params tuner_microtune_4049_fm5_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_temic_4009f_5_pal_ranges, .count = ARRAY_SIZE(tuner_temic_4009f_5_pal_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_PANASONIC_VP27 - Panasonic NTSC ------------ */ static struct tuner_range tuner_panasonic_vp27_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x01, }, - { 16 * 454.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x08, }, + { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x08, }, }; static struct tuner_params tuner_panasonic_vp27_params[] = { @@ -719,33 +648,25 @@ static struct tuner_params tuner_panasonic_vp27_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_panasonic_vp27_ntsc_ranges, .count = ARRAY_SIZE(tuner_panasonic_vp27_ntsc_ranges), - .config = 0xce, }, }; /* ------------ TUNER_LG_NTSC_TAPE - LGINNOTEK NTSC ------------ */ -static struct tuner_range tuner_lg_ntsc_tape_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x01, }, - { 16 * 442.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x04, }, -}; - static struct tuner_params tuner_lg_ntsc_tape_params[] = { { .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_lg_ntsc_tape_ranges, - .count = ARRAY_SIZE(tuner_lg_ntsc_tape_ranges), - .config = 0x8e, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), }, }; /* ------------ TUNER_TNF_8831BGFF - Philips PAL ------------ */ static struct tuner_range tuner_tnf_8831bgff_pal_ranges[] = { - { 16 * 161.25 /*MHz*/, 0xa0, }, - { 16 * 463.25 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, + { 16 * 161.25 /*MHz*/, 0x8e, 0xa0, }, + { 16 * 463.25 /*MHz*/, 0x8e, 0x90, }, + { 16 * 999.99 , 0x8e, 0x30, }, }; static struct tuner_params tuner_tnf_8831bgff_params[] = { @@ -753,16 +674,15 @@ static struct tuner_params tuner_tnf_8831bgff_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_tnf_8831bgff_pal_ranges, .count = ARRAY_SIZE(tuner_tnf_8831bgff_pal_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_MICROTUNE_4042FI5 - Microtune NTSC ------------ */ static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = { - { 16 * 162.00 /*MHz*/, 0xa2, }, - { 16 * 457.00 /*MHz*/, 0x94, }, - { 16 * 999.99 , 0x31, }, + { 16 * 162.00 /*MHz*/, 0x8e, 0xa2, }, + { 16 * 457.00 /*MHz*/, 0x8e, 0x94, }, + { 16 * 999.99 , 0x8e, 0x31, }, }; static struct tuner_params tuner_microtune_4042fi5_params[] = { @@ -770,7 +690,6 @@ static struct tuner_params tuner_microtune_4042fi5_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_microtune_4042fi5_ntsc_ranges, .count = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges), - .config = 0x8e, }, }; @@ -778,9 +697,9 @@ static struct tuner_params tuner_microtune_4042fi5_params[] = { /* ------------ TUNER_TCL_2002N - TCL NTSC ------------ */ static struct tuner_range tuner_tcl_2002n_ntsc_ranges[] = { - { 16 * 172.00 /*MHz*/, 0x01, }, - { 16 * 448.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x08, }, + { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, }; static struct tuner_params tuner_tcl_2002n_params[] = { @@ -788,34 +707,26 @@ static struct tuner_params tuner_tcl_2002n_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_tcl_2002n_ntsc_ranges, .count = ARRAY_SIZE(tuner_tcl_2002n_ntsc_ranges), - .config = 0x8e, .cb_first_if_lower_freq = 1, }, }; /* ------------ TUNER_PHILIPS_FM1256_IH3 - Philips PAL ------------ */ -static struct tuner_range tuner_philips_fm1256_ih3_pal_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x01, }, - { 16 * 442.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x04, }, -}; - static struct tuner_params tuner_philips_fm1256_ih3_params[] = { { .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_fm1256_ih3_pal_ranges, - .count = ARRAY_SIZE(tuner_philips_fm1256_ih3_pal_ranges), - .config = 0x8e, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), }, }; /* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */ static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x39, }, - { 16 * 454.00 /*MHz*/, 0x3a, }, - { 16 * 999.99 , 0x3c, }, + { 16 * 157.25 /*MHz*/, 0x8e, 0x39, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x3a, }, + { 16 * 999.99 , 0x8e, 0x3c, }, }; static struct tuner_params tuner_thomson_dtt7610_params[] = { @@ -823,16 +734,15 @@ static struct tuner_params tuner_thomson_dtt7610_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_thomson_dtt7610_ntsc_ranges, .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */ static struct tuner_range tuner_philips_fq1286_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x41, }, - { 16 * 454.00 /*MHz*/, 0x42, }, - { 16 * 999.99 , 0x04, }, + { 16 * 160.00 /*MHz*/, 0x8e, 0x41, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x42, }, + { 16 * 999.99 , 0x8e, 0x04, }, }; static struct tuner_params tuner_philips_fq1286_params[] = { @@ -840,16 +750,15 @@ static struct tuner_params tuner_philips_fq1286_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_philips_fq1286_ntsc_ranges, .count = ARRAY_SIZE(tuner_philips_fq1286_ntsc_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_TCL_2002MB - TCL PAL ------------ */ static struct tuner_range tuner_tcl_2002mb_pal_ranges[] = { - { 16 * 170.00 /*MHz*/, 0x01, }, - { 16 * 450.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x08, }, + { 16 * 170.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 450.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x08, }, }; static struct tuner_params tuner_tcl_2002mb_params[] = { @@ -857,24 +766,22 @@ static struct tuner_params tuner_tcl_2002mb_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_tcl_2002mb_pal_ranges, .count = ARRAY_SIZE(tuner_tcl_2002mb_pal_ranges), - .config = 0xce, }, }; /* ------------ TUNER_PHILIPS_FQ1216AME_MK4 - Philips PAL ------------ */ -static struct tuner_range tuner_philips_fq12_6a___mk4_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x01, }, - { 16 * 442.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x04, }, +static struct tuner_range tuner_philips_fq12_6a___mk4_pal_ranges[] = { + { 16 * 160.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 442.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x04, }, }; static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = { { .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_philips_fq12_6a___mk4_ranges, - .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_ranges), - .config = 0xce, + .ranges = tuner_philips_fq12_6a___mk4_pal_ranges, + .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_pal_ranges), }, }; @@ -883,35 +790,27 @@ static struct tuner_params tuner_philips_fq1216ame_mk4_params[] = { static struct tuner_params tuner_philips_fq1236a_mk4_params[] = { { .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_philips_fq12_6a___mk4_ranges, - .count = ARRAY_SIZE(tuner_philips_fq12_6a___mk4_ranges), - .config = 0x8e, + .ranges = tuner_fm1236_mk3_ntsc_ranges, + .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges), }, }; /* ------------ TUNER_YMEC_TVF_8531MF - Philips NTSC ------------ */ -static struct tuner_range tuner_ymec_tvf_8531mf_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0xa0, }, - { 16 * 454.00 /*MHz*/, 0x90, }, - { 16 * 999.99 , 0x30, }, -}; - static struct tuner_params tuner_ymec_tvf_8531mf_params[] = { { .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_ymec_tvf_8531mf_ntsc_ranges, - .count = ARRAY_SIZE(tuner_ymec_tvf_8531mf_ntsc_ranges), - .config = 0x8e, + .ranges = tuner_philips_ntsc_m_ranges, + .count = ARRAY_SIZE(tuner_philips_ntsc_m_ranges), }, }; /* ------------ TUNER_YMEC_TVF_5533MF - Philips NTSC ------------ */ static struct tuner_range tuner_ymec_tvf_5533mf_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x01, }, - { 16 * 454.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x04, }, + { 16 * 160.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 454.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, }; static struct tuner_params tuner_ymec_tvf_5533mf_params[] = { @@ -919,7 +818,6 @@ static struct tuner_params tuner_ymec_tvf_5533mf_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_ymec_tvf_5533mf_ntsc_ranges, .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_ntsc_ranges), - .config = 0x8e, }, }; @@ -928,9 +826,9 @@ static struct tuner_params tuner_ymec_tvf_5533mf_params[] = { /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = { - { 16 * 145.25 /*MHz*/, 0x39, }, - { 16 * 415.25 /*MHz*/, 0x3a, }, - { 16 * 999.99 , 0x3c, }, + { 16 * 145.25 /*MHz*/, 0x8e, 0x39, }, + { 16 * 415.25 /*MHz*/, 0x8e, 0x3a, }, + { 16 * 999.99 , 0x8e, 0x3c, }, }; @@ -939,42 +837,39 @@ static struct tuner_params tuner_thomson_dtt761x_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_thomson_dtt761x_ntsc_ranges, .count = ARRAY_SIZE(tuner_thomson_dtt761x_ntsc_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */ -static struct tuner_range tuner_tuner_tena_9533_di_pal_ranges[] = { - { 16 * 160.25 /*MHz*/, 0x01, }, - { 16 * 464.25 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x04, }, +static struct tuner_range tuner_tena_9533_di_pal_ranges[] = { + { 16 * 160.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 464.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, }; static struct tuner_params tuner_tena_9533_di_params[] = { { .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_tuner_tena_9533_di_pal_ranges, - .count = ARRAY_SIZE(tuner_tuner_tena_9533_di_pal_ranges), - .config = 0x8e, + .ranges = tuner_tena_9533_di_pal_ranges, + .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges), }, }; /* ------------ TUNER_PHILIPS_FMD1216ME_MK3 - Philips PAL ------------ */ static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x51, }, - { 16 * 442.00 /*MHz*/, 0x52, }, - { 16 * 999.99 , 0x54, }, + { 16 * 160.00 /*MHz*/, 0x86, 0x51, }, + { 16 * 442.00 /*MHz*/, 0x86, 0x52, }, + { 16 * 999.99 , 0x86, 0x54, }, }; -static struct tuner_params tuner_tuner_philips_fmd1216me_mk3_params[] = { +static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = { { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_philips_fmd1216me_mk3_pal_ranges, .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_pal_ranges), - .config = 0x86, }, }; @@ -982,9 +877,9 @@ static struct tuner_params tuner_tuner_philips_fmd1216me_mk3_params[] = { /* ------------ TUNER_LG_TDVS_H062F - INFINEON ATSC ------------ */ static struct tuner_range tuner_tua6034_ntsc_ranges[] = { - { 16 * 160.00 /*MHz*/, 0x01 }, - { 16 * 455.00 /*MHz*/, 0x02 }, - { 16 * 999.99 , 0x04 }, + { 16 * 160.00 /*MHz*/, 0x8e, 0x01 }, + { 16 * 455.00 /*MHz*/, 0x8e, 0x02 }, + { 16 * 999.99 , 0x8e, 0x04 }, }; @@ -993,50 +888,51 @@ static struct tuner_params tuner_tua6034_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_tua6034_ntsc_ranges, .count = ARRAY_SIZE(tuner_tua6034_ntsc_ranges), - .config = 0x8e, }, }; /* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */ -static struct tuner_range tuner_ymec_tvf66t5_b_dff_pal_ranges[] = { - { 16 * 160.25 /*MHz*/, 0x01, }, - { 16 * 464.25 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x08, }, -}; - static struct tuner_params tuner_ymec_tvf66t5_b_dff_params[] = { { .type = TUNER_PARAM_TYPE_PAL, - .ranges = tuner_ymec_tvf66t5_b_dff_pal_ranges, - .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_pal_ranges), - .config = 0x8e, + .ranges = tuner_tena_9533_di_pal_ranges, + .count = ARRAY_SIZE(tuner_tena_9533_di_pal_ranges), }, }; /* ------------ TUNER_LG_NTSC_TALN_MINI - LGINNOTEK NTSC ------------ */ -static struct tuner_range tuner_lg_taln_mini_ntsc_ranges[] = { - { 16 * 137.25 /*MHz*/, 0x01, }, - { 16 * 373.25 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x08, }, +static struct tuner_range tuner_lg_taln_ntsc_ranges[] = { + { 16 * 137.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 373.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; + +static struct tuner_range tuner_lg_taln_pal_secam_ranges[] = { + { 16 * 150.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 425.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, }; -static struct tuner_params tuner_lg_taln_mini_params[] = { +static struct tuner_params tuner_lg_taln_params[] = { { .type = TUNER_PARAM_TYPE_NTSC, - .ranges = tuner_lg_taln_mini_ntsc_ranges, - .count = ARRAY_SIZE(tuner_lg_taln_mini_ntsc_ranges), - .config = 0x8e, + .ranges = tuner_lg_taln_ntsc_ranges, + .count = ARRAY_SIZE(tuner_lg_taln_ntsc_ranges), + },{ + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_lg_taln_pal_secam_ranges, + .count = ARRAY_SIZE(tuner_lg_taln_pal_secam_ranges), }, }; /* ------------ TUNER_PHILIPS_TD1316 - Philips PAL ------------ */ static struct tuner_range tuner_philips_td1316_pal_ranges[] = { - { 16 * 160.00 /*MHz*/, 0xa1, }, - { 16 * 442.00 /*MHz*/, 0xa2, }, - { 16 * 999.99 , 0xa4, }, + { 16 * 160.00 /*MHz*/, 0xc8, 0xa1, }, + { 16 * 442.00 /*MHz*/, 0xc8, 0xa2, }, + { 16 * 999.99 , 0xc8, 0xa4, }, }; static struct tuner_params tuner_philips_td1316_params[] = { @@ -1044,34 +940,42 @@ static struct tuner_params tuner_philips_td1316_params[] = { .type = TUNER_PARAM_TYPE_PAL, .ranges = tuner_philips_td1316_pal_ranges, .count = ARRAY_SIZE(tuner_philips_td1316_pal_ranges), - .config = 0xc8, }, }; /* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */ static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x01, }, - { 16 * 454.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x04, }, + { 16 * 157.25 /*MHz*/, 0xce, 0x01, }, + { 16 * 454.00 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x04, }, }; -static struct tuner_params tuner_tuner_tuv1236d_params[] = { +static struct tuner_params tuner_tuv1236d_params[] = { { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_tuv1236d_ntsc_ranges, .count = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges), - .config = 0xce, }, }; -/* ------------ TUNER_TNF_5335MF - Philips NTSC ------------ */ +/* ------------ TUNER_TNF_xxx5 - Texas Instruments--------- */ +/* This is known to work with Tenna TVF58t5-MFF and TVF5835 MFF + * but it is expected to work also with other Tenna/Ymec + * models based on TI SN 761677 chip on both PAL and NTSC + */ + +static struct tuner_range tuner_tnf_5335_d_if_pal_ranges[] = { + { 16 * 168.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 471.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, +}; static struct tuner_range tuner_tnf_5335mf_ntsc_ranges[] = { - { 16 * 157.25 /*MHz*/, 0x01, }, - { 16 * 454.00 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x04, }, + { 16 * 169.25 /*MHz*/, 0x8e, 0x01, }, + { 16 * 469.25 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x08, }, }; static struct tuner_params tuner_tnf_5335mf_params[] = { @@ -1079,7 +983,11 @@ static struct tuner_params tuner_tnf_5335mf_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_tnf_5335mf_ntsc_ranges, .count = ARRAY_SIZE(tuner_tnf_5335mf_ntsc_ranges), - .config = 0x8e, + }, + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_tnf_5335_d_if_pal_ranges, + .count = ARRAY_SIZE(tuner_tnf_5335_d_if_pal_ranges), }, }; @@ -1087,9 +995,9 @@ static struct tuner_params tuner_tnf_5335mf_params[] = { /* ------------ TUNER_SAMSUNG_TCPN_2121P30A - Samsung NTSC ------------ */ static struct tuner_range tuner_samsung_tcpn_2121p30a_ntsc_ranges[] = { - { 16 * 175.75 /*MHz*/, 0x01, }, - { 16 * 410.25 /*MHz*/, 0x02, }, - { 16 * 999.99 , 0x08, }, + { 16 * 130.00 /*MHz*/, 0xce, 0x01, }, + { 16 * 364.50 /*MHz*/, 0xce, 0x02, }, + { 16 * 999.99 , 0xce, 0x08, }, }; static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { @@ -1097,7 +1005,22 @@ static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = { .type = TUNER_PARAM_TYPE_NTSC, .ranges = tuner_samsung_tcpn_2121p30a_ntsc_ranges, .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_ntsc_ranges), - .config = 0xce, + }, +}; + +/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */ + +static struct tuner_range tuner_thomson_fe6600_ranges[] = { + { 16 * 160.00 /*MHz*/, 0xfe, 0x11, }, + { 16 * 442.00 /*MHz*/, 0xf6, 0x12, }, + { 16 * 999.99 , 0xf6, 0x18, }, +}; + +static struct tuner_params tuner_thomson_fe6600_params[] = { + { + .type = TUNER_PARAM_TYPE_PAL, + .ranges = tuner_thomson_fe6600_ranges, + .count = ARRAY_SIZE(tuner_thomson_fe6600_ranges), }, }; @@ -1108,18 +1031,22 @@ struct tunertype tuners[] = { [TUNER_TEMIC_PAL] = { /* TEMIC PAL */ .name = "Temic PAL (4002 FH5)", .params = tuner_temic_pal_params, + .count = ARRAY_SIZE(tuner_temic_pal_params), }, [TUNER_PHILIPS_PAL_I] = { /* Philips PAL_I */ .name = "Philips PAL_I (FI1246 and compatibles)", .params = tuner_philips_pal_i_params, + .count = ARRAY_SIZE(tuner_philips_pal_i_params), }, [TUNER_PHILIPS_NTSC] = { /* Philips NTSC */ .name = "Philips NTSC (FI1236,FM1236 and compatibles)", .params = tuner_philips_ntsc_params, + .count = ARRAY_SIZE(tuner_philips_ntsc_params), }, [TUNER_PHILIPS_SECAM] = { /* Philips SECAM */ .name = "Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)", .params = tuner_philips_secam_params, + .count = ARRAY_SIZE(tuner_philips_secam_params), }, [TUNER_ABSENT] = { /* Tuner Absent */ .name = "NoTuner", @@ -1127,120 +1054,148 @@ struct tunertype tuners[] = { [TUNER_PHILIPS_PAL] = { /* Philips PAL */ .name = "Philips PAL_BG (FI1216 and compatibles)", .params = tuner_philips_pal_params, + .count = ARRAY_SIZE(tuner_philips_pal_params), }, [TUNER_TEMIC_NTSC] = { /* TEMIC NTSC */ .name = "Temic NTSC (4032 FY5)", .params = tuner_temic_ntsc_params, + .count = ARRAY_SIZE(tuner_temic_ntsc_params), }, [TUNER_TEMIC_PAL_I] = { /* TEMIC PAL_I */ .name = "Temic PAL_I (4062 FY5)", .params = tuner_temic_pal_i_params, + .count = ARRAY_SIZE(tuner_temic_pal_i_params), }, [TUNER_TEMIC_4036FY5_NTSC] = { /* TEMIC NTSC */ .name = "Temic NTSC (4036 FY5)", .params = tuner_temic_4036fy5_ntsc_params, + .count = ARRAY_SIZE(tuner_temic_4036fy5_ntsc_params), }, [TUNER_ALPS_TSBH1_NTSC] = { /* TEMIC NTSC */ .name = "Alps HSBH1", .params = tuner_alps_tsbh1_ntsc_params, + .count = ARRAY_SIZE(tuner_alps_tsbh1_ntsc_params), }, /* 10-19 */ [TUNER_ALPS_TSBE1_PAL] = { /* TEMIC PAL */ .name = "Alps TSBE1", .params = tuner_alps_tsb_1_params, + .count = ARRAY_SIZE(tuner_alps_tsb_1_params), }, [TUNER_ALPS_TSBB5_PAL_I] = { /* Alps PAL_I */ .name = "Alps TSBB5", .params = tuner_alps_tsbb5_params, + .count = ARRAY_SIZE(tuner_alps_tsbb5_params), }, [TUNER_ALPS_TSBE5_PAL] = { /* Alps PAL */ .name = "Alps TSBE5", .params = tuner_alps_tsbe5_params, + .count = ARRAY_SIZE(tuner_alps_tsbe5_params), }, [TUNER_ALPS_TSBC5_PAL] = { /* Alps PAL */ .name = "Alps TSBC5", .params = tuner_alps_tsbc5_params, + .count = ARRAY_SIZE(tuner_alps_tsbc5_params), }, [TUNER_TEMIC_4006FH5_PAL] = { /* TEMIC PAL */ .name = "Temic PAL_BG (4006FH5)", .params = tuner_temic_4006fh5_params, + .count = ARRAY_SIZE(tuner_temic_4006fh5_params), }, [TUNER_ALPS_TSHC6_NTSC] = { /* Alps NTSC */ .name = "Alps TSCH6", .params = tuner_alps_tshc6_params, + .count = ARRAY_SIZE(tuner_alps_tshc6_params), }, [TUNER_TEMIC_PAL_DK] = { /* TEMIC PAL */ .name = "Temic PAL_DK (4016 FY5)", .params = tuner_temic_pal_dk_params, + .count = ARRAY_SIZE(tuner_temic_pal_dk_params), }, [TUNER_PHILIPS_NTSC_M] = { /* Philips NTSC */ .name = "Philips NTSC_M (MK2)", .params = tuner_philips_ntsc_m_params, + .count = ARRAY_SIZE(tuner_philips_ntsc_m_params), }, [TUNER_TEMIC_4066FY5_PAL_I] = { /* TEMIC PAL_I */ .name = "Temic PAL_I (4066 FY5)", .params = tuner_temic_4066fy5_pal_i_params, + .count = ARRAY_SIZE(tuner_temic_4066fy5_pal_i_params), }, [TUNER_TEMIC_4006FN5_MULTI_PAL] = { /* TEMIC PAL */ .name = "Temic PAL* auto (4006 FN5)", .params = tuner_temic_4006fn5_multi_params, + .count = ARRAY_SIZE(tuner_temic_4006fn5_multi_params), }, /* 20-29 */ [TUNER_TEMIC_4009FR5_PAL] = { /* TEMIC PAL */ .name = "Temic PAL_BG (4009 FR5) or PAL_I (4069 FR5)", .params = tuner_temic_4009f_5_params, + .count = ARRAY_SIZE(tuner_temic_4009f_5_params), }, [TUNER_TEMIC_4039FR5_NTSC] = { /* TEMIC NTSC */ .name = "Temic NTSC (4039 FR5)", .params = tuner_temic_4039fr5_params, + .count = ARRAY_SIZE(tuner_temic_4039fr5_params), }, [TUNER_TEMIC_4046FM5] = { /* TEMIC PAL */ .name = "Temic PAL/SECAM multi (4046 FM5)", .params = tuner_temic_4046fm5_params, + .count = ARRAY_SIZE(tuner_temic_4046fm5_params), }, [TUNER_PHILIPS_PAL_DK] = { /* Philips PAL */ .name = "Philips PAL_DK (FI1256 and compatibles)", .params = tuner_philips_pal_dk_params, + .count = ARRAY_SIZE(tuner_philips_pal_dk_params), }, [TUNER_PHILIPS_FQ1216ME] = { /* Philips PAL */ .name = "Philips PAL/SECAM multi (FQ1216ME)", .params = tuner_philips_fq1216me_params, + .count = ARRAY_SIZE(tuner_philips_fq1216me_params), }, [TUNER_LG_PAL_I_FM] = { /* LGINNOTEK PAL_I */ .name = "LG PAL_I+FM (TAPC-I001D)", .params = tuner_lg_pal_i_fm_params, + .count = ARRAY_SIZE(tuner_lg_pal_i_fm_params), }, [TUNER_LG_PAL_I] = { /* LGINNOTEK PAL_I */ .name = "LG PAL_I (TAPC-I701D)", .params = tuner_lg_pal_i_params, + .count = ARRAY_SIZE(tuner_lg_pal_i_params), }, [TUNER_LG_NTSC_FM] = { /* LGINNOTEK NTSC */ .name = "LG NTSC+FM (TPI8NSR01F)", .params = tuner_lg_ntsc_fm_params, + .count = ARRAY_SIZE(tuner_lg_ntsc_fm_params), }, [TUNER_LG_PAL_FM] = { /* LGINNOTEK PAL */ .name = "LG PAL_BG+FM (TPI8PSB01D)", .params = tuner_lg_pal_fm_params, + .count = ARRAY_SIZE(tuner_lg_pal_fm_params), }, [TUNER_LG_PAL] = { /* LGINNOTEK PAL */ .name = "LG PAL_BG (TPI8PSB11D)", .params = tuner_lg_pal_params, + .count = ARRAY_SIZE(tuner_lg_pal_params), }, /* 30-39 */ [TUNER_TEMIC_4009FN5_MULTI_PAL_FM] = { /* TEMIC PAL */ .name = "Temic PAL* auto + FM (4009 FN5)", .params = tuner_temic_4009_fn5_multi_pal_fm_params, + .count = ARRAY_SIZE(tuner_temic_4009_fn5_multi_pal_fm_params), }, [TUNER_SHARP_2U5JF5540_NTSC] = { /* SHARP NTSC */ .name = "SHARP NTSC_JP (2U5JF5540)", .params = tuner_sharp_2u5jf5540_params, + .count = ARRAY_SIZE(tuner_sharp_2u5jf5540_params), }, [TUNER_Samsung_PAL_TCPM9091PD27] = { /* Samsung PAL */ .name = "Samsung PAL TCPM9091PD27", .params = tuner_samsung_pal_tcpm9091pd27_params, + .count = ARRAY_SIZE(tuner_samsung_pal_tcpm9091pd27_params), }, [TUNER_MT2032] = { /* Microtune PAL|NTSC */ .name = "MT20xx universal", @@ -1248,86 +1203,106 @@ struct tunertype tuners[] = { [TUNER_TEMIC_4106FH5] = { /* TEMIC PAL */ .name = "Temic PAL_BG (4106 FH5)", .params = tuner_temic_4106fh5_params, + .count = ARRAY_SIZE(tuner_temic_4106fh5_params), }, [TUNER_TEMIC_4012FY5] = { /* TEMIC PAL */ .name = "Temic PAL_DK/SECAM_L (4012 FY5)", .params = tuner_temic_4012fy5_params, + .count = ARRAY_SIZE(tuner_temic_4012fy5_params), }, [TUNER_TEMIC_4136FY5] = { /* TEMIC NTSC */ .name = "Temic NTSC (4136 FY5)", .params = tuner_temic_4136_fy5_params, + .count = ARRAY_SIZE(tuner_temic_4136_fy5_params), }, [TUNER_LG_PAL_NEW_TAPC] = { /* LGINNOTEK PAL */ .name = "LG PAL (newer TAPC series)", .params = tuner_lg_pal_new_tapc_params, + .count = ARRAY_SIZE(tuner_lg_pal_new_tapc_params), }, [TUNER_PHILIPS_FM1216ME_MK3] = { /* Philips PAL */ .name = "Philips PAL/SECAM multi (FM1216ME MK3)", .params = tuner_fm1216me_mk3_params, + .count = ARRAY_SIZE(tuner_fm1216me_mk3_params), }, [TUNER_LG_NTSC_NEW_TAPC] = { /* LGINNOTEK NTSC */ .name = "LG NTSC (newer TAPC series)", .params = tuner_lg_ntsc_new_tapc_params, + .count = ARRAY_SIZE(tuner_lg_ntsc_new_tapc_params), }, /* 40-49 */ [TUNER_HITACHI_NTSC] = { /* HITACHI NTSC */ .name = "HITACHI V7-J180AT", .params = tuner_hitachi_ntsc_params, + .count = ARRAY_SIZE(tuner_hitachi_ntsc_params), }, [TUNER_PHILIPS_PAL_MK] = { /* Philips PAL */ .name = "Philips PAL_MK (FI1216 MK)", .params = tuner_philips_pal_mk_params, + .count = ARRAY_SIZE(tuner_philips_pal_mk_params), }, [TUNER_PHILIPS_ATSC] = { /* Philips ATSC */ .name = "Philips 1236D ATSC/NTSC dual in", .params = tuner_philips_atsc_params, + .count = ARRAY_SIZE(tuner_philips_atsc_params), }, [TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */ .name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)", .params = tuner_fm1236_mk3_params, + .count = ARRAY_SIZE(tuner_fm1236_mk3_params), }, [TUNER_PHILIPS_4IN1] = { /* Philips NTSC */ .name = "Philips 4 in 1 (ATI TV Wonder Pro/Conexant)", .params = tuner_philips_4in1_params, + .count = ARRAY_SIZE(tuner_philips_4in1_params), }, [TUNER_MICROTUNE_4049FM5] = { /* Microtune PAL */ .name = "Microtune 4049 FM5", .params = tuner_microtune_4049_fm5_params, + .count = ARRAY_SIZE(tuner_microtune_4049_fm5_params), }, [TUNER_PANASONIC_VP27] = { /* Panasonic NTSC */ .name = "Panasonic VP27s/ENGE4324D", .params = tuner_panasonic_vp27_params, + .count = ARRAY_SIZE(tuner_panasonic_vp27_params), }, [TUNER_LG_NTSC_TAPE] = { /* LGINNOTEK NTSC */ .name = "LG NTSC (TAPE series)", .params = tuner_lg_ntsc_tape_params, + .count = ARRAY_SIZE(tuner_lg_ntsc_tape_params), }, [TUNER_TNF_8831BGFF] = { /* Philips PAL */ .name = "Tenna TNF 8831 BGFF)", .params = tuner_tnf_8831bgff_params, + .count = ARRAY_SIZE(tuner_tnf_8831bgff_params), }, [TUNER_MICROTUNE_4042FI5] = { /* Microtune NTSC */ .name = "Microtune 4042 FI5 ATSC/NTSC dual in", .params = tuner_microtune_4042fi5_params, + .count = ARRAY_SIZE(tuner_microtune_4042fi5_params), }, /* 50-59 */ [TUNER_TCL_2002N] = { /* TCL NTSC */ .name = "TCL 2002N", .params = tuner_tcl_2002n_params, + .count = ARRAY_SIZE(tuner_tcl_2002n_params), }, [TUNER_PHILIPS_FM1256_IH3] = { /* Philips PAL */ .name = "Philips PAL/SECAM_D (FM 1256 I-H3)", .params = tuner_philips_fm1256_ih3_params, + .count = ARRAY_SIZE(tuner_philips_fm1256_ih3_params), }, [TUNER_THOMSON_DTT7610] = { /* THOMSON ATSC */ .name = "Thomson DTT 7610 (ATSC/NTSC)", .params = tuner_thomson_dtt7610_params, + .count = ARRAY_SIZE(tuner_thomson_dtt7610_params), }, [TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */ .name = "Philips FQ1286", .params = tuner_philips_fq1286_params, + .count = ARRAY_SIZE(tuner_philips_fq1286_params), }, [TUNER_PHILIPS_TDA8290] = { /* Philips PAL|NTSC */ .name = "tda8290+75", @@ -1335,22 +1310,27 @@ struct tunertype tuners[] = { [TUNER_TCL_2002MB] = { /* TCL PAL */ .name = "TCL 2002MB", .params = tuner_tcl_2002mb_params, + .count = ARRAY_SIZE(tuner_tcl_2002mb_params), }, [TUNER_PHILIPS_FQ1216AME_MK4] = { /* Philips PAL */ .name = "Philips PAL/SECAM multi (FQ1216AME MK4)", .params = tuner_philips_fq1216ame_mk4_params, + .count = ARRAY_SIZE(tuner_philips_fq1216ame_mk4_params), }, [TUNER_PHILIPS_FQ1236A_MK4] = { /* Philips NTSC */ .name = "Philips FQ1236A MK4", .params = tuner_philips_fq1236a_mk4_params, + .count = ARRAY_SIZE(tuner_philips_fq1236a_mk4_params), }, [TUNER_YMEC_TVF_8531MF] = { /* Philips NTSC */ .name = "Ymec TVision TVF-8531MF/8831MF/8731MF", .params = tuner_ymec_tvf_8531mf_params, + .count = ARRAY_SIZE(tuner_ymec_tvf_8531mf_params), }, [TUNER_YMEC_TVF_5533MF] = { /* Philips NTSC */ .name = "Ymec TVision TVF-5533MF", .params = tuner_ymec_tvf_5533mf_params, + .count = ARRAY_SIZE(tuner_ymec_tvf_5533mf_params), }, /* 60-69 */ @@ -1358,10 +1338,12 @@ struct tunertype tuners[] = { /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */ .name = "Thomson DTT 761X (ATSC/NTSC)", .params = tuner_thomson_dtt761x_params, + .count = ARRAY_SIZE(tuner_thomson_dtt761x_params), }, [TUNER_TENA_9533_DI] = { /* Philips PAL */ .name = "Tena TNF9533-D/IF/TNF9533-B/DF", .params = tuner_tena_9533_di_params, + .count = ARRAY_SIZE(tuner_tena_9533_di_params), }, [TUNER_TEA5767] = { /* Philips RADIO */ .name = "Philips TEA5767HN FM Radio", @@ -1369,37 +1351,54 @@ struct tunertype tuners[] = { }, [TUNER_PHILIPS_FMD1216ME_MK3] = { /* Philips PAL */ .name = "Philips FMD1216ME MK3 Hybrid Tuner", - .params = tuner_tuner_philips_fmd1216me_mk3_params, + .params = tuner_philips_fmd1216me_mk3_params, + .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params), }, [TUNER_LG_TDVS_H062F] = { /* LGINNOTEK ATSC */ .name = "LG TDVS-H062F/TUA6034", .params = tuner_tua6034_params, + .count = ARRAY_SIZE(tuner_tua6034_params), }, [TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */ .name = "Ymec TVF66T5-B/DFF", .params = tuner_ymec_tvf66t5_b_dff_params, + .count = ARRAY_SIZE(tuner_ymec_tvf66t5_b_dff_params), }, - [TUNER_LG_NTSC_TALN_MINI] = { /* LGINNOTEK NTSC */ - .name = "LG NTSC (TALN mini series)", - .params = tuner_lg_taln_mini_params, + [TUNER_LG_TALN] = { /* LGINNOTEK NTSC / PAL / SECAM */ + .name = "LG TALN series", + .params = tuner_lg_taln_params, + .count = ARRAY_SIZE(tuner_lg_taln_params), }, [TUNER_PHILIPS_TD1316] = { /* Philips PAL */ .name = "Philips TD1316 Hybrid Tuner", .params = tuner_philips_td1316_params, + .count = ARRAY_SIZE(tuner_philips_td1316_params), }, [TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */ .name = "Philips TUV1236D ATSC/NTSC dual in", - .params = tuner_tuner_tuv1236d_params, + .params = tuner_tuv1236d_params, + .count = ARRAY_SIZE(tuner_tuv1236d_params), }, - [TUNER_TNF_5335MF] = { /* Philips NTSC */ - .name = "Tena TNF 5335 MF", + [TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */ + .name = "Tena TNF 5335 and similar models", .params = tuner_tnf_5335mf_params, + .count = ARRAY_SIZE(tuner_tnf_5335mf_params), }, /* 70-79 */ [TUNER_SAMSUNG_TCPN_2121P30A] = { /* Samsung NTSC */ .name = "Samsung TCPN 2121P30A", .params = tuner_samsung_tcpn_2121p30a_params, + .count = ARRAY_SIZE(tuner_samsung_tcpn_2121p30a_params), + }, + [TUNER_XCEIVE_XC3028] = { /* Xceive 3028 */ + .name = "Xceive xc3028", + /* see xc3028.c for details */ + }, + [TUNER_THOMSON_FE6600] = { /* Thomson PAL / DVB-T */ + .name = "Thomson FE6600", + .params = tuner_thomson_fe6600_params, + .count = ARRAY_SIZE(tuner_thomson_fe6600_params), }, }; diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c index c8e5ad0e818..4efb01bb44a 100644 --- a/drivers/media/video/tvaudio.c +++ b/drivers/media/video/tvaudio.c @@ -130,6 +130,7 @@ struct CHIPSTATE { struct timer_list wt; int done; int watch_stereo; + int audmode; }; /* ---------------------------------------------------------------------- */ @@ -1514,6 +1515,7 @@ static int chip_attach(struct i2c_adapter *adap, int addr, int kind) chip->type = desc-chiplist; chip->shadow.count = desc->registers+1; chip->prevmode = -1; + chip->audmode = V4L2_TUNER_MODE_LANG1; /* register */ i2c_attach_client(&chip->c); @@ -1671,6 +1673,8 @@ static int chip_command(struct i2c_client *client, struct v4l2_tuner *vt = arg; int mode = 0; + if (chip->radio) + break; switch (vt->audmode) { case V4L2_TUNER_MODE_MONO: mode = VIDEO_SOUND_MONO; @@ -1685,8 +1689,9 @@ static int chip_command(struct i2c_client *client, mode = VIDEO_SOUND_LANG2; break; default: - break; + return -EINVAL; } + chip->audmode = vt->audmode; if (desc->setmode && mode) { chip->watch_stereo = 0; @@ -1704,7 +1709,7 @@ static int chip_command(struct i2c_client *client, if (chip->radio) break; - vt->audmode = 0; + vt->audmode = chip->audmode; vt->rxsubchans = 0; vt->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; @@ -1716,19 +1721,12 @@ static int chip_command(struct i2c_client *client, vt->rxsubchans |= V4L2_TUNER_SUB_MONO; if (mode & VIDEO_SOUND_STEREO) vt->rxsubchans |= V4L2_TUNER_SUB_STEREO; + /* Note: for SAP it should be mono/lang2 or stereo/lang2. + When this module is converted fully to v4l2, then this + should change for those chips that can detect SAP. */ if (mode & VIDEO_SOUND_LANG1) - vt->rxsubchans |= V4L2_TUNER_SUB_LANG1 | - V4L2_TUNER_SUB_LANG2; - - mode = chip->mode; - if (mode & VIDEO_SOUND_MONO) - vt->audmode = V4L2_TUNER_MODE_MONO; - if (mode & VIDEO_SOUND_STEREO) - vt->audmode = V4L2_TUNER_MODE_STEREO; - if (mode & VIDEO_SOUND_LANG1) - vt->audmode = V4L2_TUNER_MODE_LANG1; - if (mode & VIDEO_SOUND_LANG2) - vt->audmode = V4L2_TUNER_MODE_LANG2; + vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | + V4L2_TUNER_SUB_LANG2; break; } diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c index 1864423b304..69d0fe159f4 100644 --- a/drivers/media/video/tvp5150.c +++ b/drivers/media/video/tvp5150.c @@ -1,8 +1,8 @@ /* - * tvp5150 - Texas Instruments TVP5150A(M) video decoder driver + * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder driver * - * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br) - * This code is placed under the terms of the GNU General Public License + * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 */ #include <linux/i2c.h> @@ -13,10 +13,11 @@ #include "tvp5150_reg.h" -MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); /* standard i2c insmod options */ +MODULE_DESCRIPTION("Texas Instruments TVP5150A video decoder driver"); MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); +/* standard i2c insmod options */ static unsigned short normal_i2c[] = { 0xb8 >> 1, 0xba >> 1, @@ -29,6 +30,9 @@ static int debug = 0; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "Debug level (0-1)"); +#define tvp5150_err(fmt, arg...) do { \ + printk(KERN_ERR "%s %d-%04x: " fmt, c->driver->driver.name, \ + i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0) #define tvp5150_info(fmt, arg...) do { \ printk(KERN_INFO "%s %d-%04x: " fmt, c->driver->driver.name, \ i2c_adapter_id(c->adapter), c->addr , ## arg); } while (0) @@ -84,7 +88,7 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = { struct tvp5150 { struct i2c_client *client; - int norm; + v4l2_std_id norm; /* Current set standard */ int input; int enable; int bright; @@ -125,310 +129,155 @@ static inline void tvp5150_write(struct i2c_client *c, unsigned char addr, tvp5150_dbg(0, "i2c i/o error: rc == %d (should be 2)\n", rc); } +static void dump_reg_range(struct i2c_client *c, char *s, u8 init, const u8 end,int max_line) +{ + int i=0; + + while (init!=(u8)(end+1)) { + if ((i%max_line) == 0) { + if (i>0) + printk("\n"); + printk("tvp5150: %s reg 0x%02x = ",s,init); + } + printk("%02x ",tvp5150_read(c, init)); + + init++; + i++; + } + printk("\n"); +} + static void dump_reg(struct i2c_client *c) { printk("tvp5150: Video input source selection #1 = 0x%02x\n", - tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1)); + tvp5150_read(c, TVP5150_VD_IN_SRC_SEL_1)); printk("tvp5150: Analog channel controls = 0x%02x\n", - tvp5150_read(c, TVP5150_ANAL_CHL_CTL)); + tvp5150_read(c, TVP5150_ANAL_CHL_CTL)); printk("tvp5150: Operation mode controls = 0x%02x\n", - tvp5150_read(c, TVP5150_OP_MODE_CTL)); + tvp5150_read(c, TVP5150_OP_MODE_CTL)); printk("tvp5150: Miscellaneous controls = 0x%02x\n", - tvp5150_read(c, TVP5150_MISC_CTL)); - printk("tvp5150: Autoswitch mask: TVP5150A / TVP5150AM = 0x%02x\n", - tvp5150_read(c, TVP5150_AUTOSW_MSK)); + tvp5150_read(c, TVP5150_MISC_CTL)); + printk("tvp5150: Autoswitch mask= 0x%02x\n", + tvp5150_read(c, TVP5150_AUTOSW_MSK)); printk("tvp5150: Color killer threshold control = 0x%02x\n", - tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL)); - printk("tvp5150: Luminance processing control #1 = 0x%02x\n", - tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1)); - printk("tvp5150: Luminance processing control #2 = 0x%02x\n", - tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2)); + tvp5150_read(c, TVP5150_COLOR_KIL_THSH_CTL)); + printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n", + tvp5150_read(c, TVP5150_LUMA_PROC_CTL_1), + tvp5150_read(c, TVP5150_LUMA_PROC_CTL_2), + tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3)); printk("tvp5150: Brightness control = 0x%02x\n", - tvp5150_read(c, TVP5150_BRIGHT_CTL)); + tvp5150_read(c, TVP5150_BRIGHT_CTL)); printk("tvp5150: Color saturation control = 0x%02x\n", - tvp5150_read(c, TVP5150_SATURATION_CTL)); + tvp5150_read(c, TVP5150_SATURATION_CTL)); printk("tvp5150: Hue control = 0x%02x\n", - tvp5150_read(c, TVP5150_HUE_CTL)); + tvp5150_read(c, TVP5150_HUE_CTL)); printk("tvp5150: Contrast control = 0x%02x\n", - tvp5150_read(c, TVP5150_CONTRAST_CTL)); + tvp5150_read(c, TVP5150_CONTRAST_CTL)); printk("tvp5150: Outputs and data rates select = 0x%02x\n", - tvp5150_read(c, TVP5150_DATA_RATE_SEL)); - printk("tvp5150: Luminance processing control #3 = 0x%02x\n", - tvp5150_read(c, TVP5150_LUMA_PROC_CTL_3)); + tvp5150_read(c, TVP5150_DATA_RATE_SEL)); printk("tvp5150: Configuration shared pins = 0x%02x\n", - tvp5150_read(c, TVP5150_CONF_SHARED_PIN)); - printk("tvp5150: Active video cropping start MSB = 0x%02x\n", - tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB)); - printk("tvp5150: Active video cropping start LSB = 0x%02x\n", - tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB)); - printk("tvp5150: Active video cropping stop MSB = 0x%02x\n", - tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB)); - printk("tvp5150: Active video cropping stop LSB = 0x%02x\n", - tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB)); + tvp5150_read(c, TVP5150_CONF_SHARED_PIN)); + printk("tvp5150: Active video cropping start = 0x%02x%02x\n", + tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_MSB), + tvp5150_read(c, TVP5150_ACT_VD_CROP_ST_LSB)); + printk("tvp5150: Active video cropping stop = 0x%02x%02x\n", + tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_MSB), + tvp5150_read(c, TVP5150_ACT_VD_CROP_STP_LSB)); printk("tvp5150: Genlock/RTC = 0x%02x\n", - tvp5150_read(c, TVP5150_GENLOCK)); + tvp5150_read(c, TVP5150_GENLOCK)); printk("tvp5150: Horizontal sync start = 0x%02x\n", - tvp5150_read(c, TVP5150_HORIZ_SYNC_START)); + tvp5150_read(c, TVP5150_HORIZ_SYNC_START)); printk("tvp5150: Vertical blanking start = 0x%02x\n", - tvp5150_read(c, TVP5150_VERT_BLANKING_START)); + tvp5150_read(c, TVP5150_VERT_BLANKING_START)); printk("tvp5150: Vertical blanking stop = 0x%02x\n", - tvp5150_read(c, TVP5150_VERT_BLANKING_STOP)); - printk("tvp5150: Chrominance processing control #1 = 0x%02x\n", - tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1)); - printk("tvp5150: Chrominance processing control #2 = 0x%02x\n", - tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2)); + tvp5150_read(c, TVP5150_VERT_BLANKING_STOP)); + printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n", + tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_1), + tvp5150_read(c, TVP5150_CHROMA_PROC_CTL_2)); printk("tvp5150: Interrupt reset register B = 0x%02x\n", - tvp5150_read(c, TVP5150_INT_RESET_REG_B)); + tvp5150_read(c, TVP5150_INT_RESET_REG_B)); printk("tvp5150: Interrupt enable register B = 0x%02x\n", - tvp5150_read(c, TVP5150_INT_ENABLE_REG_B)); + tvp5150_read(c, TVP5150_INT_ENABLE_REG_B)); printk("tvp5150: Interrupt configuration register B = 0x%02x\n", - tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B)); + tvp5150_read(c, TVP5150_INTT_CONFIG_REG_B)); printk("tvp5150: Video standard = 0x%02x\n", - tvp5150_read(c, TVP5150_VIDEO_STD)); - printk("tvp5150: Cb gain factor = 0x%02x\n", - tvp5150_read(c, TVP5150_CB_GAIN_FACT)); - printk("tvp5150: Cr gain factor = 0x%02x\n", - tvp5150_read(c, TVP5150_CR_GAIN_FACTOR)); + tvp5150_read(c, TVP5150_VIDEO_STD)); + printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n", + tvp5150_read(c, TVP5150_CB_GAIN_FACT), + tvp5150_read(c, TVP5150_CR_GAIN_FACTOR)); printk("tvp5150: Macrovision on counter = 0x%02x\n", - tvp5150_read(c, TVP5150_MACROVISION_ON_CTR)); + tvp5150_read(c, TVP5150_MACROVISION_ON_CTR)); printk("tvp5150: Macrovision off counter = 0x%02x\n", - tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR)); - printk("tvp5150: revision select (TVP5150AM1 only) = 0x%02x\n", - tvp5150_read(c, TVP5150_REV_SELECT)); - printk("tvp5150: MSB of device ID = 0x%02x\n", - tvp5150_read(c, TVP5150_MSB_DEV_ID)); - printk("tvp5150: LSB of device ID = 0x%02x\n", - tvp5150_read(c, TVP5150_LSB_DEV_ID)); - printk("tvp5150: ROM major version = 0x%02x\n", - tvp5150_read(c, TVP5150_ROM_MAJOR_VER)); - printk("tvp5150: ROM minor version = 0x%02x\n", - tvp5150_read(c, TVP5150_ROM_MINOR_VER)); - printk("tvp5150: Vertical line count MSB = 0x%02x\n", - tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB)); - printk("tvp5150: Vertical line count LSB = 0x%02x\n", - tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB)); + tvp5150_read(c, TVP5150_MACROVISION_OFF_CTR)); + printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n", + (tvp5150_read(c, TVP5150_REV_SELECT)&1)?3:4); + printk("tvp5150: Device ID = %02x%02x\n", + tvp5150_read(c, TVP5150_MSB_DEV_ID), + tvp5150_read(c, TVP5150_LSB_DEV_ID)); + printk("tvp5150: ROM version = (hex) %02x.%02x\n", + tvp5150_read(c, TVP5150_ROM_MAJOR_VER), + tvp5150_read(c, TVP5150_ROM_MINOR_VER)); + printk("tvp5150: Vertical line count = 0x%02x%02x\n", + tvp5150_read(c, TVP5150_VERT_LN_COUNT_MSB), + tvp5150_read(c, TVP5150_VERT_LN_COUNT_LSB)); printk("tvp5150: Interrupt status register B = 0x%02x\n", - tvp5150_read(c, TVP5150_INT_STATUS_REG_B)); + tvp5150_read(c, TVP5150_INT_STATUS_REG_B)); printk("tvp5150: Interrupt active register B = 0x%02x\n", - tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B)); - printk("tvp5150: Status register #1 = 0x%02x\n", - tvp5150_read(c, TVP5150_STATUS_REG_1)); - printk("tvp5150: Status register #2 = 0x%02x\n", - tvp5150_read(c, TVP5150_STATUS_REG_2)); - printk("tvp5150: Status register #3 = 0x%02x\n", - tvp5150_read(c, TVP5150_STATUS_REG_3)); - printk("tvp5150: Status register #4 = 0x%02x\n", - tvp5150_read(c, TVP5150_STATUS_REG_4)); - printk("tvp5150: Status register #5 = 0x%02x\n", - tvp5150_read(c, TVP5150_STATUS_REG_5)); - printk("tvp5150: Closed caption data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_CC_DATA_REG1)); - printk("tvp5150: Closed caption data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_CC_DATA_REG2)); - printk("tvp5150: Closed caption data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_CC_DATA_REG3)); - printk("tvp5150: Closed caption data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_CC_DATA_REG4)); - printk("tvp5150: WSS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_WSS_DATA_REG1)); - printk("tvp5150: WSS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_WSS_DATA_REG2)); - printk("tvp5150: WSS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_WSS_DATA_REG3)); - printk("tvp5150: WSS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_WSS_DATA_REG4)); - printk("tvp5150: WSS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_WSS_DATA_REG5)); - printk("tvp5150: WSS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_WSS_DATA_REG6)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG1)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG2)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG3)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG4)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG5)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG6)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG7)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG8)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG9)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG10)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG11)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG12)); - printk("tvp5150: VPS data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VPS_DATA_REG13)); - printk("tvp5150: VITC data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VITC_DATA_REG1)); - printk("tvp5150: VITC data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VITC_DATA_REG2)); - printk("tvp5150: VITC data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VITC_DATA_REG3)); - printk("tvp5150: VITC data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VITC_DATA_REG4)); - printk("tvp5150: VITC data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VITC_DATA_REG5)); - printk("tvp5150: VITC data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VITC_DATA_REG6)); - printk("tvp5150: VITC data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VITC_DATA_REG7)); - printk("tvp5150: VITC data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VITC_DATA_REG8)); - printk("tvp5150: VITC data registers = 0x%02x\n", - tvp5150_read(c, TVP5150_VITC_DATA_REG9)); - printk("tvp5150: VBI FIFO read data = 0x%02x\n", - tvp5150_read(c, TVP5150_VBI_FIFO_READ_DATA)); - printk("tvp5150: Teletext filter 1 = 0x%02x\n", - tvp5150_read(c, TVP5150_TELETEXT_FIL_1_1)); - printk("tvp5150: Teletext filter 1 = 0x%02x\n", - tvp5150_read(c, TVP5150_TELETEXT_FIL_1_2)); - printk("tvp5150: Teletext filter 1 = 0x%02x\n", - tvp5150_read(c, TVP5150_TELETEXT_FIL_1_3)); - printk("tvp5150: Teletext filter 1 = 0x%02x\n", - tvp5150_read(c, TVP5150_TELETEXT_FIL_1_4)); - printk("tvp5150: Teletext filter 1 = 0x%02x\n", - tvp5150_read(c, TVP5150_TELETEXT_FIL_1_5)); - printk("tvp5150: Teletext filter 2 = 0x%02x\n", - tvp5150_read(c, TVP5150_TELETEXT_FIL_2_1)); - printk("tvp5150: Teletext filter 2 = 0x%02x\n", - tvp5150_read(c, TVP5150_TELETEXT_FIL_2_2)); - printk("tvp5150: Teletext filter 2 = 0x%02x\n", - tvp5150_read(c, TVP5150_TELETEXT_FIL_2_3)); - printk("tvp5150: Teletext filter 2 = 0x%02x\n", - tvp5150_read(c, TVP5150_TELETEXT_FIL_2_4)); - printk("tvp5150: Teletext filter 2 = 0x%02x\n", - tvp5150_read(c, TVP5150_TELETEXT_FIL_2_5)); + tvp5150_read(c, TVP5150_INT_ACTIVE_REG_B)); + printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n", + tvp5150_read(c, TVP5150_STATUS_REG_1), + tvp5150_read(c, TVP5150_STATUS_REG_2), + tvp5150_read(c, TVP5150_STATUS_REG_3), + tvp5150_read(c, TVP5150_STATUS_REG_4), + tvp5150_read(c, TVP5150_STATUS_REG_5)); + + dump_reg_range(c,"Teletext filter 1", TVP5150_TELETEXT_FIL1_INI, + TVP5150_TELETEXT_FIL1_END,8); + dump_reg_range(c,"Teletext filter 2", TVP5150_TELETEXT_FIL2_INI, + TVP5150_TELETEXT_FIL2_END,8); + printk("tvp5150: Teletext filter enable = 0x%02x\n", - tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA)); + tvp5150_read(c, TVP5150_TELETEXT_FIL_ENA)); printk("tvp5150: Interrupt status register A = 0x%02x\n", - tvp5150_read(c, TVP5150_INT_STATUS_REG_A)); + tvp5150_read(c, TVP5150_INT_STATUS_REG_A)); printk("tvp5150: Interrupt enable register A = 0x%02x\n", - tvp5150_read(c, TVP5150_INT_ENABLE_REG_A)); + tvp5150_read(c, TVP5150_INT_ENABLE_REG_A)); printk("tvp5150: Interrupt configuration = 0x%02x\n", - tvp5150_read(c, TVP5150_INT_CONF)); - printk("tvp5150: VDP configuration RAM data = 0x%02x\n", - tvp5150_read(c, TVP5150_VDP_CONF_RAM_DATA)); - printk("tvp5150: Configuration RAM address low byte = 0x%02x\n", - tvp5150_read(c, TVP5150_CONF_RAM_ADDR_LOW)); - printk("tvp5150: Configuration RAM address high byte = 0x%02x\n", - tvp5150_read(c, TVP5150_CONF_RAM_ADDR_HIGH)); + tvp5150_read(c, TVP5150_INT_CONF)); printk("tvp5150: VDP status register = 0x%02x\n", - tvp5150_read(c, TVP5150_VDP_STATUS_REG)); + tvp5150_read(c, TVP5150_VDP_STATUS_REG)); printk("tvp5150: FIFO word count = 0x%02x\n", - tvp5150_read(c, TVP5150_FIFO_WORD_COUNT)); + tvp5150_read(c, TVP5150_FIFO_WORD_COUNT)); printk("tvp5150: FIFO interrupt threshold = 0x%02x\n", - tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD)); + tvp5150_read(c, TVP5150_FIFO_INT_THRESHOLD)); printk("tvp5150: FIFO reset = 0x%02x\n", - tvp5150_read(c, TVP5150_FIFO_RESET)); + tvp5150_read(c, TVP5150_FIFO_RESET)); printk("tvp5150: Line number interrupt = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_NUMBER_INT)); - printk("tvp5150: Pixel alignment register low byte = 0x%02x\n", - tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW)); - printk("tvp5150: Pixel alignment register high byte = 0x%02x\n", - tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH)); + tvp5150_read(c, TVP5150_LINE_NUMBER_INT)); + printk("tvp5150: Pixel alignment register = 0x%02x%02x\n", + tvp5150_read(c, TVP5150_PIX_ALIGN_REG_HIGH), + tvp5150_read(c, TVP5150_PIX_ALIGN_REG_LOW)); printk("tvp5150: FIFO output control = 0x%02x\n", - tvp5150_read(c, TVP5150_FIFO_OUT_CTRL)); - printk("tvp5150: Full field enable 1 = 0x%02x\n", - tvp5150_read(c, TVP5150_FULL_FIELD_ENA_1)); - printk("tvp5150: Full field enable 2 = 0x%02x\n", - tvp5150_read(c, TVP5150_FULL_FIELD_ENA_2)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_1)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_2)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_3)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_4)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_5)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_6)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_7)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_8)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_9)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_10)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_11)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_12)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_13)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_14)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_15)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_16)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_17)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_18)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_19)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_20)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_21)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_22)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_23)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_24)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_25)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_27)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_28)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_29)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_30)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_31)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_32)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_33)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_34)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_35)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_36)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_37)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_38)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_39)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_40)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_41)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_42)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_43)); - printk("tvp5150: Line mode registers = 0x%02x\n", - tvp5150_read(c, TVP5150_LINE_MODE_REG_44)); + tvp5150_read(c, TVP5150_FIFO_OUT_CTRL)); + printk("tvp5150: Full field enable = 0x%02x\n", + tvp5150_read(c, TVP5150_FULL_FIELD_ENA)); printk("tvp5150: Full field mode register = 0x%02x\n", - tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG)); + tvp5150_read(c, TVP5150_FULL_FIELD_MODE_REG)); + + dump_reg_range(c,"CC data", TVP5150_CC_DATA_INI, + TVP5150_CC_DATA_END,8); + + dump_reg_range(c,"WSS data", TVP5150_WSS_DATA_INI, + TVP5150_WSS_DATA_END,8); + + dump_reg_range(c,"VPS data", TVP5150_VPS_DATA_INI, + TVP5150_VPS_DATA_END,8); + + dump_reg_range(c,"VITC data", TVP5150_VITC_DATA_INI, + TVP5150_VITC_DATA_END,10); + + dump_reg_range(c,"Line mode", TVP5150_LINE_MODE_INI, + TVP5150_LINE_MODE_END,8); } /**************************************************************************** @@ -593,10 +442,10 @@ static const struct i2c_reg_value tvp5150_init_default[] = { TVP5150_FIFO_OUT_CTRL,0x01 }, { /* 0xcf */ - TVP5150_FULL_FIELD_ENA_1,0x00 + TVP5150_FULL_FIELD_ENA,0x00 }, { /* 0xd0 */ - TVP5150_FULL_FIELD_ENA_2,0x00 + TVP5150_LINE_MODE_INI,0x00 }, { /* 0xfc */ TVP5150_FULL_FIELD_MODE_REG,0x7f @@ -629,54 +478,101 @@ static const struct i2c_reg_value tvp5150_init_enable[] = { } }; +struct tvp5150_vbi_type { + unsigned int vbi_type; + unsigned int ini_line; + unsigned int end_line; + unsigned int by_field :1; +}; + struct i2c_vbi_ram_value { u16 reg; - unsigned char values[26]; + struct tvp5150_vbi_type type; + unsigned char values[16]; }; +/* This struct have the values for each supported VBI Standard + * by + tvp5150_vbi_types should follow the same order as vbi_ram_default + * value 0 means rom position 0x10, value 1 means rom position 0x30 + * and so on. There are 16 possible locations from 0 to 15. + */ + static struct i2c_vbi_ram_value vbi_ram_default[] = { - {0x010, /* WST SECAM 6 */ - { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x26, 0xe6, 0xb4, 0x0e, 0x0, 0x0, 0x0, 0x10, 0x0 } + {0x010, /* Teletext, SECAM, WST System A */ + {V4L2_SLICED_TELETEXT_SECAM,6,23,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x26, + 0xe6, 0xb4, 0x0e, 0x00, 0x00, 0x00, 0x10, 0x00 } }, - {0x030, /* WST PAL B 6 */ - { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x2b, 0xa6, 0x72, 0x10, 0x0, 0x0, 0x0, 0x10, 0x0 } + {0x030, /* Teletext, PAL, WST System B */ + {V4L2_SLICED_TELETEXT_PAL_B,6,22,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x2b, + 0xa6, 0x72, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00 } }, - {0x050, /* WST PAL C 6 */ - { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0xa6, 0x98, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 } + {0x050, /* Teletext, PAL, WST System C */ + {V4L2_SLICED_TELETEXT_PAL_C,6,22,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, + 0xa6, 0x98, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } }, - {0x070, /* WST NTSC 6 */ - { 0xaa, 0xaa, 0xff, 0xff , 0x27, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 } + {0x070, /* Teletext, NTSC, WST System B */ + {V4L2_SLICED_TELETEXT_NTSC_B,10,21,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0x27, 0x2e, 0x20, 0x23, + 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } }, - {0x090, /* NABTS, NTSC 6 */ - { 0xaa, 0xaa, 0xff, 0xff , 0xe7, 0x2e, 0x20, 0x22, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x15, 0x0 } + {0x090, /* Tetetext, NTSC NABTS System C */ + {V4L2_SLICED_TELETEXT_NTSC_C,10,21,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0xe7, 0x2e, 0x20, 0x22, + 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x15, 0x00 } }, - {0x0b0, /* NABTS, NTSC-J 6 */ - { 0xaa, 0xaa, 0xff, 0xff , 0xa7, 0x2e, 0x20, 0x23, 0x69, 0x93, 0x0d, 0x0, 0x0, 0x0, 0x10, 0x0 } + {0x0b0, /* Teletext, NTSC-J, NABTS System D */ + {V4L2_SLICED_TELETEXT_NTSC_D,10,21,1}, + { 0xaa, 0xaa, 0xff, 0xff, 0xa7, 0x2e, 0x20, 0x23, + 0x69, 0x93, 0x0d, 0x00, 0x00, 0x00, 0x10, 0x00 } }, - {0x0d0, /* CC, PAL/SECAM 6 */ - { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0xa6, 0x7b, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 } + {0x0d0, /* Closed Caption, PAL/SECAM */ + {V4L2_SLICED_CAPTION_625,22,22,1}, + { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, + 0xa6, 0x7b, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } }, - {0x0f0, /* CC, NTSC 6 */ - { 0xaa, 0x2a, 0xff, 0x3f , 0x04, 0x51, 0x6e, 0x02, 0x69, 0x8c, 0x09, 0x0, 0x0, 0x0, 0x27, 0x0 } + {0x0f0, /* Closed Caption, NTSC */ + {V4L2_SLICED_CAPTION_525,21,21,1}, + { 0xaa, 0x2a, 0xff, 0x3f, 0x04, 0x51, 0x6e, 0x02, + 0x69, 0x8c, 0x09, 0x00, 0x00, 0x00, 0x27, 0x00 } }, - {0x110, /* WSS, PAL/SECAM 6 */ - { 0x5b, 0x55, 0xc5, 0xff , 0x0, 0x71, 0x6e, 0x42, 0xa6, 0xcd, 0x0f, 0x0, 0x0, 0x0, 0x3a, 0x0 } + {0x110, /* Wide Screen Signal, PAL/SECAM */ + {V4L2_SLICED_WSS_625,23,23,1}, + { 0x5b, 0x55, 0xc5, 0xff, 0x00, 0x71, 0x6e, 0x42, + 0xa6, 0xcd, 0x0f, 0x00, 0x00, 0x00, 0x3a, 0x00 } }, - {0x130, /* WSS, NTSC C */ - { 0x38, 0x00, 0x3f, 0x00 , 0x0, 0x71, 0x6e, 0x43, 0x69, 0x7c, 0x08, 0x0, 0x0, 0x0, 0x39, 0x0 } + {0x130, /* Wide Screen Signal, NTSC C */ + {V4L2_SLICED_WSS_525,20,20,1}, + { 0x38, 0x00, 0x3f, 0x00, 0x00, 0x71, 0x6e, 0x43, + 0x69, 0x7c, 0x08, 0x00, 0x00, 0x00, 0x39, 0x00 } }, - {0x150, /* VITC, PAL/SECAM 6 */ - { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0xa6, 0x85, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 } + {0x150, /* Vertical Interval Timecode (VITC), PAL/SECAM */ + {V4l2_SLICED_VITC_625,6,22,0}, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, + 0xa6, 0x85, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } }, - {0x170, /* VITC, NTSC 6 */ - { 0x0, 0x0, 0x0, 0x0 , 0x0, 0x8f, 0x6d, 0x49, 0x69, 0x94, 0x08, 0x0, 0x0, 0x0, 0x4c, 0x0 } + {0x170, /* Vertical Interval Timecode (VITC), NTSC */ + {V4l2_SLICED_VITC_525,10,20,0}, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x6d, 0x49, + 0x69, 0x94, 0x08, 0x00, 0x00, 0x00, 0x4c, 0x00 } }, + {0x190, /* Video Program System (VPS), PAL */ + {V4L2_SLICED_VPS,16,16,0}, + { 0xaa, 0xaa, 0xff, 0xff, 0xba, 0xce, 0x2b, 0x0d, + 0xa6, 0xda, 0x0b, 0x00, 0x00, 0x00, 0x60, 0x00 } + }, + /* 0x1d0 User programmable */ + + /* End of struct */ { (u16)-1 } }; static int tvp5150_write_inittab(struct i2c_client *c, - const struct i2c_reg_value *regs) + const struct i2c_reg_value *regs) { while (regs->reg != 0xff) { tvp5150_write(c, regs->reg, regs->value); @@ -686,15 +582,15 @@ static int tvp5150_write_inittab(struct i2c_client *c, } static int tvp5150_vdp_init(struct i2c_client *c, - const struct i2c_vbi_ram_value *regs) + const struct i2c_vbi_ram_value *regs) { unsigned int i; /* Disable Full Field */ - tvp5150_write(c, TVP5150_FULL_FIELD_ENA_1, 0); + tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0); /* Before programming, Line mode should be at 0xff */ - for (i=TVP5150_FULL_FIELD_ENA_2; i<=TVP5150_LINE_MODE_REG_44; i++) + for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++) tvp5150_write(c, i, 0xff); /* Load Ram Table */ @@ -710,6 +606,117 @@ static int tvp5150_vdp_init(struct i2c_client *c, return 0; } +/* Fills VBI capabilities based on i2c_vbi_ram_value struct */ +static void tvp5150_vbi_get_cap(const struct i2c_vbi_ram_value *regs, + struct v4l2_sliced_vbi_cap *cap) +{ + int line; + + memset(cap, 0, sizeof *cap); + + while (regs->reg != (u16)-1 ) { + for (line=regs->type.ini_line;line<=regs->type.end_line;line++) { + cap->service_lines[0][line] |= regs->type.vbi_type; + } + cap->service_set |= regs->type.vbi_type; + + regs++; + } +} + +/* Set vbi processing + * type - one of tvp5150_vbi_types + * line - line to gather data + * fields: bit 0 field1, bit 1, field2 + * flags (default=0xf0) is a bitmask, were set means: + * bit 7: enable filtering null bytes on CC + * bit 6: send data also to FIFO + * bit 5: don't allow data with errors on FIFO + * bit 4: enable ECC when possible + * pix_align = pix alignment: + * LSB = field1 + * MSB = field2 + */ +static int tvp5150_set_vbi(struct i2c_client *c, + const struct i2c_vbi_ram_value *regs, + unsigned int type,u8 flags, int line, + const int fields) +{ + struct tvp5150 *decoder = i2c_get_clientdata(c); + v4l2_std_id std=decoder->norm; + u8 reg; + int pos=0; + + if (std == V4L2_STD_ALL) { + tvp5150_err("VBI can't be configured without knowing number of lines\n"); + return 0; + } else if (std && V4L2_STD_625_50) { + /* Don't follow NTSC Line number convension */ + line += 3; + } + + if (line<6||line>27) + return 0; + + while (regs->reg != (u16)-1 ) { + if ((type & regs->type.vbi_type) && + (line>=regs->type.ini_line) && + (line<=regs->type.end_line)) { + type=regs->type.vbi_type; + break; + } + + regs++; + pos++; + } + if (regs->reg == (u16)-1) + return 0; + + type=pos | (flags & 0xf0); + reg=((line-6)<<1)+TVP5150_LINE_MODE_INI; + + if (fields&1) { + tvp5150_write(c, reg, type); + } + + if (fields&2) { + tvp5150_write(c, reg+1, type); + } + + return type; +} + +static int tvp5150_get_vbi(struct i2c_client *c, + const struct i2c_vbi_ram_value *regs, int line) +{ + struct tvp5150 *decoder = i2c_get_clientdata(c); + v4l2_std_id std=decoder->norm; + u8 reg; + int pos, type=0; + + if (std == V4L2_STD_ALL) { + tvp5150_err("VBI can't be configured without knowing number of lines\n"); + return 0; + } else if (std && V4L2_STD_625_50) { + /* Don't follow NTSC Line number convension */ + line += 3; + } + + if (line<6||line>27) + return 0; + + reg=((line-6)<<1)+TVP5150_LINE_MODE_INI; + + pos=tvp5150_read(c, reg)&0x0f; + if (pos<0x0f) + type=regs[pos].type.vbi_type; + + pos=tvp5150_read(c, reg+1)&0x0f; + if (pos<0x0f) + type|=regs[pos].type.vbi_type; + + return type; +} static int tvp5150_set_std(struct i2c_client *c, v4l2_std_id std) { struct tvp5150 *decoder = i2c_get_clientdata(c); @@ -854,6 +861,69 @@ static int tvp5150_command(struct i2c_client *c, *(v4l2_std_id *)arg = decoder->norm; break; + case VIDIOC_G_SLICED_VBI_CAP: + { + struct v4l2_sliced_vbi_cap *cap = arg; + tvp5150_dbg(1, "VIDIOC_G_SLICED_VBI_CAP\n"); + + tvp5150_vbi_get_cap(vbi_ram_default, cap); + break; + } + case VIDIOC_S_FMT: + { + struct v4l2_format *fmt; + struct v4l2_sliced_vbi_format *svbi; + int i; + + fmt = arg; + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + svbi = &fmt->fmt.sliced; + if (svbi->service_set != 0) { + for (i = 0; i <= 23; i++) { + svbi->service_lines[1][i] = 0; + + svbi->service_lines[0][i]=tvp5150_set_vbi(c, + vbi_ram_default, + svbi->service_lines[0][i],0xf0,i,3); + } + /* Enables FIFO */ + tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,1); + } else { + /* Disables FIFO*/ + tvp5150_write(c, TVP5150_FIFO_OUT_CTRL,0); + + /* Disable Full Field */ + tvp5150_write(c, TVP5150_FULL_FIELD_ENA, 0); + + /* Disable Line modes */ + for (i=TVP5150_LINE_MODE_INI; i<=TVP5150_LINE_MODE_END; i++) + tvp5150_write(c, i, 0xff); + } + break; + } + case VIDIOC_G_FMT: + { + struct v4l2_format *fmt; + struct v4l2_sliced_vbi_format *svbi; + + int i, mask=0; + + fmt = arg; + if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + svbi = &fmt->fmt.sliced; + memset(svbi, 0, sizeof(*svbi)); + + for (i = 0; i <= 23; i++) { + svbi->service_lines[0][i]=tvp5150_get_vbi(c, + vbi_ram_default,i); + mask|=svbi->service_lines[0][i]; + } + svbi->service_set=mask; + break; + } + #ifdef CONFIG_VIDEO_ADV_DEBUG case VIDIOC_INT_G_REGISTER: { @@ -878,6 +948,7 @@ static int tvp5150_command(struct i2c_client *c, } #endif + case VIDIOC_LOG_STATUS: case DECODER_DUMP: dump_reg(c); break; @@ -1097,7 +1168,7 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter, rv = i2c_attach_client(c); - core->norm = V4L2_STD_ALL; + core->norm = V4L2_STD_ALL; /* Default is autodetect */ core->input = 2; core->enable = 1; core->bright = 32768; diff --git a/drivers/media/video/tvp5150_reg.h b/drivers/media/video/tvp5150_reg.h index cd45c1ded78..4240043c0b2 100644 --- a/drivers/media/video/tvp5150_reg.h +++ b/drivers/media/video/tvp5150_reg.h @@ -1,3 +1,10 @@ +/* + * tvp5150 - Texas Instruments TVP5150A/AM1 video decoder registers + * + * Copyright (c) 2005,2006 Mauro Carvalho Chehab (mchehab@infradead.org) + * This code is placed under the terms of the GNU General Public License v2 + */ + #define TVP5150_VD_IN_SRC_SEL_1 0x00 /* Video input source selection #1 */ #define TVP5150_ANAL_CHL_CTL 0x01 /* Analog channel controls */ #define TVP5150_OP_MODE_CTL 0x02 /* Operation mode controls */ @@ -64,49 +71,32 @@ #define TVP5150_STATUS_REG_4 0x8b /* Status register #4 */ #define TVP5150_STATUS_REG_5 0x8c /* Status register #5 */ /* Reserved 8Dh-8Fh */ -#define TVP5150_CC_DATA_REG1 0x90 /* Closed caption data registers */ -#define TVP5150_CC_DATA_REG2 0x91 /* Closed caption data registers */ -#define TVP5150_CC_DATA_REG3 0x92 /* Closed caption data registers */ -#define TVP5150_CC_DATA_REG4 0x93 /* Closed caption data registers */ -#define TVP5150_WSS_DATA_REG1 0X94 /* WSS data registers */ -#define TVP5150_WSS_DATA_REG2 0X95 /* WSS data registers */ -#define TVP5150_WSS_DATA_REG3 0X96 /* WSS data registers */ -#define TVP5150_WSS_DATA_REG4 0X97 /* WSS data registers */ -#define TVP5150_WSS_DATA_REG5 0X98 /* WSS data registers */ -#define TVP5150_WSS_DATA_REG6 0X99 /* WSS data registers */ -#define TVP5150_VPS_DATA_REG1 0x9a /* VPS data registers */ -#define TVP5150_VPS_DATA_REG2 0x9b /* VPS data registers */ -#define TVP5150_VPS_DATA_REG3 0x9c /* VPS data registers */ -#define TVP5150_VPS_DATA_REG4 0x9d /* VPS data registers */ -#define TVP5150_VPS_DATA_REG5 0x9e /* VPS data registers */ -#define TVP5150_VPS_DATA_REG6 0x9f /* VPS data registers */ -#define TVP5150_VPS_DATA_REG7 0xa0 /* VPS data registers */ -#define TVP5150_VPS_DATA_REG8 0xa1 /* VPS data registers */ -#define TVP5150_VPS_DATA_REG9 0xa2 /* VPS data registers */ -#define TVP5150_VPS_DATA_REG10 0xa3 /* VPS data registers */ -#define TVP5150_VPS_DATA_REG11 0xa4 /* VPS data registers */ -#define TVP5150_VPS_DATA_REG12 0xa5 /* VPS data registers */ -#define TVP5150_VPS_DATA_REG13 0xa6 /* VPS data registers */ -#define TVP5150_VITC_DATA_REG1 0xa7 /* VITC data registers */ -#define TVP5150_VITC_DATA_REG2 0xa8 /* VITC data registers */ -#define TVP5150_VITC_DATA_REG3 0xa9 /* VITC data registers */ -#define TVP5150_VITC_DATA_REG4 0xaa /* VITC data registers */ -#define TVP5150_VITC_DATA_REG5 0xab /* VITC data registers */ -#define TVP5150_VITC_DATA_REG6 0xac /* VITC data registers */ -#define TVP5150_VITC_DATA_REG7 0xad /* VITC data registers */ -#define TVP5150_VITC_DATA_REG8 0xae /* VITC data registers */ -#define TVP5150_VITC_DATA_REG9 0xaf /* VITC data registers */ + /* Closed caption data registers */ +#define TVP5150_CC_DATA_INI 0x90 +#define TVP5150_CC_DATA_END 0x93 + + /* WSS data registers */ +#define TVP5150_WSS_DATA_INI 0x94 +#define TVP5150_WSS_DATA_END 0x99 + +/* VPS data registers */ +#define TVP5150_VPS_DATA_INI 0x9a +#define TVP5150_VPS_DATA_END 0xa6 + +/* VITC data registers */ +#define TVP5150_VITC_DATA_INI 0xa7 +#define TVP5150_VITC_DATA_END 0xaf + #define TVP5150_VBI_FIFO_READ_DATA 0xb0 /* VBI FIFO read data */ -#define TVP5150_TELETEXT_FIL_1_1 0xb1 /* Teletext filter 1 */ -#define TVP5150_TELETEXT_FIL_1_2 0xb2 /* Teletext filter 1 */ -#define TVP5150_TELETEXT_FIL_1_3 0xb3 /* Teletext filter 1 */ -#define TVP5150_TELETEXT_FIL_1_4 0xb4 /* Teletext filter 1 */ -#define TVP5150_TELETEXT_FIL_1_5 0xb5 /* Teletext filter 1 */ -#define TVP5150_TELETEXT_FIL_2_1 0xb6 /* Teletext filter 2 */ -#define TVP5150_TELETEXT_FIL_2_2 0xb7 /* Teletext filter 2 */ -#define TVP5150_TELETEXT_FIL_2_3 0xb8 /* Teletext filter 2 */ -#define TVP5150_TELETEXT_FIL_2_4 0xb9 /* Teletext filter 2 */ -#define TVP5150_TELETEXT_FIL_2_5 0xba /* Teletext filter 2 */ + +/* Teletext filter 1 */ +#define TVP5150_TELETEXT_FIL1_INI 0xb1 +#define TVP5150_TELETEXT_FIL1_END 0xb5 + +/* Teletext filter 2 */ +#define TVP5150_TELETEXT_FIL2_INI 0xb6 +#define TVP5150_TELETEXT_FIL2_END 0xba + #define TVP5150_TELETEXT_FIL_ENA 0xbb /* Teletext filter enable */ /* Reserved BCh-BFh */ #define TVP5150_INT_STATUS_REG_A 0xc0 /* Interrupt status register A */ @@ -124,50 +114,11 @@ #define TVP5150_PIX_ALIGN_REG_HIGH 0xcc /* Pixel alignment register high byte */ #define TVP5150_FIFO_OUT_CTRL 0xcd /* FIFO output control */ /* Reserved CEh */ -#define TVP5150_FULL_FIELD_ENA_1 0xcf /* Full field enable 1 */ -#define TVP5150_FULL_FIELD_ENA_2 0xd0 /* Full field enable 2 */ -#define TVP5150_LINE_MODE_REG_1 0xd1 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_2 0xd2 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_3 0xd3 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_4 0xd4 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_5 0xd5 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_6 0xd6 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_7 0xd7 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_8 0xd8 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_9 0xd9 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_10 0xda /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_11 0xdb /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_12 0xdc /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_13 0xdd /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_14 0xde /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_15 0xdf /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_16 0xe0 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_17 0xe1 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_18 0xe2 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_19 0xe3 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_20 0xe4 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_21 0xe5 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_22 0xe6 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_23 0xe7 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_24 0xe8 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_25 0xe9 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_27 0xea /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_28 0xeb /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_29 0xec /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_30 0xed /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_31 0xee /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_32 0xef /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_33 0xf0 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_34 0xf1 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_35 0xf2 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_36 0xf3 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_37 0xf4 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_38 0xf5 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_39 0xf6 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_40 0xf7 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_41 0xf8 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_42 0xf9 /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_43 0xfa /* Line mode registers */ -#define TVP5150_LINE_MODE_REG_44 0xfb /* Line mode registers */ +#define TVP5150_FULL_FIELD_ENA 0xcf /* Full field enable 1 */ + +/* Line mode registers */ +#define TVP5150_LINE_MODE_INI 0xd0 +#define TVP5150_LINE_MODE_END 0xfb + #define TVP5150_FULL_FIELD_MODE_REG 0xfc /* Full field mode register */ /* Reserved FDh-FFh */ diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c index cd2c4475525..95a6e47c99f 100644 --- a/drivers/media/video/v4l2-common.c +++ b/drivers/media/video/v4l2-common.c @@ -97,7 +97,7 @@ int v4l2_video_std_construct(struct v4l2_standard *vs, memset(vs, 0, sizeof(struct v4l2_standard)); vs->index = index; vs->id = id; - if (id & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) { + if (id & V4L2_STD_525_60) { vs->frameperiod.numerator = 1001; vs->frameperiod.denominator = 30000; vs->framelines = 525; @@ -110,7 +110,6 @@ int v4l2_video_std_construct(struct v4l2_standard *vs, return 0; } - /* ----------------------------------------------------------------- */ /* priority handling */ @@ -171,7 +170,7 @@ int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority *local) /* ----------------------------------------------------------------- */ -/* some arrays for pretty-printing debug messages */ +/* some arrays for pretty-printing debug messages of enum types */ char *v4l2_field_names[] = { [V4L2_FIELD_ANY] = "any", @@ -192,6 +191,14 @@ char *v4l2_type_names[] = { [V4L2_BUF_TYPE_VBI_OUTPUT] = "vbi-out", }; +static char *v4l2_memory_names[] = { + [V4L2_MEMORY_MMAP] = "mmap", + [V4L2_MEMORY_USERPTR] = "userptr", + [V4L2_MEMORY_OVERLAY] = "overlay", +}; + +#define prt_names(a,arr) (((a)>=0)&&((a)<ARRAY_SIZE(arr)))?arr[a]:"unknown" + /* ------------------------------------------------------------------ */ /* debug help functions */ @@ -324,6 +331,15 @@ static const char *v4l2_int_ioctls[] = { }; #define V4L2_INT_IOCTLS ARRAY_SIZE(v4l2_int_ioctls) +static void v4l_print_pix_fmt (char *s, struct v4l2_pix_format *fmt) +{ + printk ("%s: width=%d, height=%d, format=%d, field=%s, " + "bytesperline=%d sizeimage=%d, colorspace=%d\n", s, + fmt->width,fmt->height,fmt->pixelformat, + prt_names(fmt->field,v4l2_field_names), + fmt->bytesperline,fmt->sizeimage,fmt->colorspace); +}; + /* Common ioctl debug function. This function can be used by external ioctl messages as well as internal V4L ioctl */ void v4l_printk_ioctl(unsigned int cmd) @@ -362,6 +378,541 @@ void v4l_printk_ioctl(unsigned int cmd) } } +/* Common ioctl debug function. This function can be used by + external ioctl messages as well as internal V4L ioctl and its + arguments */ +void v4l_printk_ioctl_arg(char *s,unsigned int cmd, void *arg) +{ + printk(s); + printk(": "); + v4l_printk_ioctl(cmd); + switch (cmd) { + case VIDIOC_INT_G_CHIP_IDENT: + { + enum v4l2_chip_ident *p=arg; + printk ("%s: chip ident=%d\n", s, *p); + break; + } + case VIDIOC_G_PRIORITY: + case VIDIOC_S_PRIORITY: + { + enum v4l2_priority *p=arg; + printk ("%s: priority=%d\n", s, *p); + break; + } + case VIDIOC_INT_S_TUNER_MODE: + { + enum v4l2_tuner_type *p=arg; + printk ("%s: tuner type=%d\n", s, *p); + break; + } + case DECODER_SET_VBI_BYPASS: + case DECODER_ENABLE_OUTPUT: + case DECODER_GET_STATUS: + case DECODER_SET_OUTPUT: + case DECODER_SET_INPUT: + case DECODER_SET_GPIO: + case DECODER_SET_NORM: + case VIDIOCCAPTURE: + case VIDIOCSYNC: + case VIDIOCSWRITEMODE: + case TUNER_SET_TYPE_ADDR: + case TUNER_SET_STANDBY: + case TDA9887_SET_CONFIG: + case AUDC_SET_INPUT: + case VIDIOC_OVERLAY_OLD: + case VIDIOC_STREAMOFF: + case VIDIOC_G_OUTPUT: + case VIDIOC_S_OUTPUT: + case VIDIOC_STREAMON: + case VIDIOC_G_INPUT: + case VIDIOC_OVERLAY: + case VIDIOC_S_INPUT: + { + int *p=arg; + printk ("%s: value=%d\n", s, *p); + break; + } + case MSP_SET_MATRIX: + { + struct msp_matrix *p=arg; + printk ("%s: input=%d, output=%d\n", s, p->input, p->output); + break; + } + case VIDIOC_G_AUDIO: + case VIDIOC_S_AUDIO: + case VIDIOC_ENUMAUDIO: + case VIDIOC_G_AUDIO_OLD: + { + struct v4l2_audio *p=arg; + + printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", + s,p->index, p->name,p->capability, p->mode); + break; + } + case VIDIOC_G_AUDOUT: + case VIDIOC_S_AUDOUT: + case VIDIOC_ENUMAUDOUT: + case VIDIOC_G_AUDOUT_OLD: + { + struct v4l2_audioout *p=arg; + printk ("%s: index=%d, name=%s, capability=%d, mode=%d\n", s, + p->index, p->name, p->capability,p->mode); + break; + } + case VIDIOC_QBUF: + case VIDIOC_DQBUF: + case VIDIOC_QUERYBUF: + { + struct v4l2_buffer *p=arg; + struct v4l2_timecode *tc=&p->timecode; + printk ("%s: %02ld:%02d:%02d.%08ld index=%d, type=%s, " + "bytesused=%d, flags=0x%08d, " + "field=%0d, sequence=%d, memory=%s, offset/userptr=0x%08lx\n", + s, + (p->timestamp.tv_sec/3600), + (int)(p->timestamp.tv_sec/60)%60, + (int)(p->timestamp.tv_sec%60), + p->timestamp.tv_usec, + p->index, + prt_names(p->type,v4l2_type_names), + p->bytesused,p->flags, + p->field,p->sequence, + prt_names(p->memory,v4l2_memory_names), + p->m.userptr); + printk ("%s: timecode= %02d:%02d:%02d type=%d, " + "flags=0x%08d, frames=%d, userbits=0x%08x", + s,tc->hours,tc->minutes,tc->seconds, + tc->type, tc->flags, tc->frames, (__u32) tc->userbits); + break; + } + case VIDIOC_QUERYCAP: + { + struct v4l2_capability *p=arg; + printk ("%s: driver=%s, card=%s, bus=%s, version=%d, " + "capabilities=%d\n", s, + p->driver,p->card,p->bus_info, + p->version, + p->capabilities); + break; + } + case VIDIOC_G_CTRL: + case VIDIOC_S_CTRL: + case VIDIOC_S_CTRL_OLD: + { + struct v4l2_control *p=arg; + printk ("%s: id=%d, value=%d\n", s, p->id, p->value); + break; + } + case VIDIOC_G_CROP: + case VIDIOC_S_CROP: + { + struct v4l2_crop *p=arg; + /*FIXME: Should also show rect structs */ + printk ("%s: type=%d\n", s, p->type); + break; + } + case VIDIOC_CROPCAP: + case VIDIOC_CROPCAP_OLD: + { + struct v4l2_cropcap *p=arg; + /*FIXME: Should also show rect structs */ + printk ("%s: type=%d\n", s, p->type); + break; + } + case VIDIOC_INT_DECODE_VBI_LINE: + { + struct v4l2_decode_vbi_line *p=arg; + printk ("%s: is_second_field=%d, ptr=0x%08lx, line=%d, " + "type=%d\n", s, + p->is_second_field,(unsigned long)p->p,p->line,p->type); + break; + } + case VIDIOC_ENUM_FMT: + { + struct v4l2_fmtdesc *p=arg; + printk ("%s: index=%d, type=%d, flags=%d, description=%s," + " pixelformat=%d\n", s, + p->index, p->type, p->flags,p->description, + p->pixelformat); + + break; + } + case VIDIOC_G_FMT: + case VIDIOC_S_FMT: + case VIDIOC_TRY_FMT: + { + struct v4l2_format *p=arg; + printk ("%s: type=%s\n", s, + prt_names(p->type,v4l2_type_names)); + switch (p->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + v4l_print_pix_fmt (s, &p->fmt.pix); + break; + default: + break; + } + } + case VIDIOC_G_FBUF: + case VIDIOC_S_FBUF: + { + struct v4l2_framebuffer *p=arg; + printk ("%s: capability=%d, flags=%d, base=0x%08lx\n", s, + p->capability,p->flags, (unsigned long)p->base); + v4l_print_pix_fmt (s, &p->fmt); + break; + } + case VIDIOC_G_FREQUENCY: + case VIDIOC_S_FREQUENCY: + { + struct v4l2_frequency *p=arg; + printk ("%s: tuner=%d, type=%d, frequency=%d\n", s, + p->tuner,p->type,p->frequency); + break; + } + case VIDIOC_ENUMINPUT: + { + struct v4l2_input *p=arg; + printk ("%s: index=%d, name=%s, type=%d, audioset=%d, " + "tuner=%d, std=%lld, status=%d\n", s, + p->index,p->name,p->type,p->audioset, + p->tuner,p->std, + p->status); + break; + } + case VIDIOC_G_JPEGCOMP: + case VIDIOC_S_JPEGCOMP: + { + struct v4l2_jpegcompression *p=arg; + printk ("%s: quality=%d, APPn=%d, APP_len=%d, COM_len=%d," + " jpeg_markers=%d\n", s, + p->quality,p->APPn,p->APP_len, + p->COM_len,p->jpeg_markers); + break; + } + case VIDIOC_G_MODULATOR: + case VIDIOC_S_MODULATOR: + { + struct v4l2_modulator *p=arg; + printk ("%s: index=%d, name=%s, capability=%d, rangelow=%d," + " rangehigh=%d, txsubchans=%d\n", s, + p->index, p->name,p->capability,p->rangelow, + p->rangehigh,p->txsubchans); + break; + } + case VIDIOC_G_MPEGCOMP: + case VIDIOC_S_MPEGCOMP: + { + struct v4l2_mpeg_compression *p=arg; + /*FIXME: Several fields not shown */ + printk ("%s: ts_pid_pmt=%d, ts_pid_audio=%d, ts_pid_video=%d, " + "ts_pid_pcr=%d, ps_size=%d, au_sample_rate=%d, " + "au_pesid=%c, vi_frame_rate=%d, vi_frames_per_gop=%d, " + "vi_bframes_count=%d, vi_pesid=%c\n", s, + p->ts_pid_pmt,p->ts_pid_audio, p->ts_pid_video, + p->ts_pid_pcr, p->ps_size, p->au_sample_rate, + p->au_pesid, p->vi_frame_rate, + p->vi_frames_per_gop, p->vi_bframes_count, + p->vi_pesid); + break; + } + case VIDIOC_ENUMOUTPUT: + { + struct v4l2_output *p=arg; + printk ("%s: index=%d, name=%s,type=%d, audioset=%d, " + "modulator=%d, std=%lld\n", + s,p->index,p->name,p->type,p->audioset, + p->modulator,p->std); + break; + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl *p=arg; + printk ("%s: id=%d, type=%d, name=%s, min/max=%d/%d," + " step=%d, default=%d, flags=0x%08x\n", s, + p->id,p->type,p->name,p->minimum,p->maximum, + p->step,p->default_value,p->flags); + break; + } + case VIDIOC_QUERYMENU: + { + struct v4l2_querymenu *p=arg; + printk ("%s: id=%d, index=%d, name=%s\n", s, + p->id,p->index,p->name); + break; + } + case VIDIOC_INT_G_REGISTER: + case VIDIOC_INT_S_REGISTER: + { + struct v4l2_register *p=arg; + printk ("%s: i2c_id=%d, reg=%lu, val=%d\n", s, + p->i2c_id,p->reg,p->val); + + break; + } + case VIDIOC_REQBUFS: + { + struct v4l2_requestbuffers *p=arg; + printk ("%s: count=%d, type=%s, memory=%s\n", s, + p->count, + prt_names(p->type,v4l2_type_names), + prt_names(p->memory,v4l2_memory_names)); + break; + } + case VIDIOC_INT_S_AUDIO_ROUTING: + case VIDIOC_INT_S_VIDEO_ROUTING: + case VIDIOC_INT_G_AUDIO_ROUTING: + case VIDIOC_INT_G_VIDEO_ROUTING: + { + struct v4l2_routing *p=arg; + printk ("%s: input=%d, output=%d\n", s, p->input, p->output); + break; + } + case VIDIOC_G_SLICED_VBI_CAP: + { + struct v4l2_sliced_vbi_cap *p=arg; + printk ("%s: service_set=%d\n", s, + p->service_set); + break; + } + case VIDIOC_INT_S_VBI_DATA: + case VIDIOC_INT_G_VBI_DATA: + { + struct v4l2_sliced_vbi_data *p=arg; + printk ("%s: id=%d, field=%d, line=%d\n", s, + p->id, p->field, p->line); + break; + } + case VIDIOC_ENUMSTD: + { + struct v4l2_standard *p=arg; + printk ("%s: index=%d, id=%lld, name=%s, fps=%d/%d, framelines=%d\n", s, + p->index, p->id, p->name, + p->frameperiod.numerator, + p->frameperiod.denominator, + p->framelines); + + break; + } + case VIDIOC_G_PARM: + case VIDIOC_S_PARM: + case VIDIOC_S_PARM_OLD: + { + struct v4l2_streamparm *p=arg; + printk ("%s: type=%d\n", s, p->type); + + break; + } + case VIDIOC_G_TUNER: + case VIDIOC_S_TUNER: + { + struct v4l2_tuner *p=arg; + printk ("%s: index=%d, name=%s, type=%d, capability=%d, " + "rangelow=%d, rangehigh=%d, signal=%d, afc=%d, " + "rxsubchans=%d, audmode=%d\n", s, + p->index, p->name, p->type, + p->capability, p->rangelow,p->rangehigh, + p->rxsubchans, p->audmode, p->signal, + p->afc); + break; + } + case VIDIOCGVBIFMT: + case VIDIOCSVBIFMT: + { + struct vbi_format *p=arg; + printk ("%s: sampling_rate=%d, samples_per_line=%d, " + "sample_format=%d, start=%d/%d, count=%d/%d, flags=%d\n", s, + p->sampling_rate,p->samples_per_line, + p->sample_format,p->start[0],p->start[1], + p->count[0],p->count[1],p->flags); + break; + } + case VIDIOCGAUDIO: + case VIDIOCSAUDIO: + { + struct video_audio *p=arg; + printk ("%s: audio=%d, volume=%d, bass=%d, treble=%d, " + "flags=%d, name=%s, mode=%d, balance=%d, step=%d\n", + s,p->audio,p->volume,p->bass, p->treble, + p->flags,p->name,p->mode,p->balance,p->step); + break; + } + case VIDIOCGFBUF: + case VIDIOCSFBUF: + { + struct video_buffer *p=arg; + printk ("%s: base=%08lx, height=%d, width=%d, depth=%d, " + "bytesperline=%d\n", s, + (unsigned long) p->base, p->height, p->width, + p->depth,p->bytesperline); + break; + } + case VIDIOCGCAP: + { + struct video_capability *p=arg; + printk ("%s: name=%s, type=%d, channels=%d, audios=%d, " + "maxwidth=%d, maxheight=%d, minwidth=%d, minheight=%d\n", + s,p->name,p->type,p->channels,p->audios, + p->maxwidth,p->maxheight,p->minwidth, + p->minheight); + + break; + } + case VIDIOCGCAPTURE: + case VIDIOCSCAPTURE: + { + struct video_capture *p=arg; + printk ("%s: x=%d, y=%d, width=%d, height=%d, decimation=%d," + " flags=%d\n", s, + p->x, p->y,p->width, p->height, + p->decimation,p->flags); + break; + } + case VIDIOCGCHAN: + case VIDIOCSCHAN: + { + struct video_channel *p=arg; + printk ("%s: channel=%d, name=%s, tuners=%d, flags=%d, " + "type=%d, norm=%d\n", s, + p->channel,p->name,p->tuners, + p->flags,p->type,p->norm); + + break; + } + case VIDIOCSMICROCODE: + { + struct video_code *p=arg; + printk ("%s: loadwhat=%s, datasize=%d\n", s, + p->loadwhat,p->datasize); + break; + } + case DECODER_GET_CAPABILITIES: + { + struct video_decoder_capability *p=arg; + printk ("%s: flags=%d, inputs=%d, outputs=%d\n", s, + p->flags,p->inputs,p->outputs); + break; + } + case DECODER_INIT: + { + struct video_decoder_init *p=arg; + printk ("%s: len=%c\n", s, p->len); + break; + } + case VIDIOCGPLAYINFO: + { + struct video_info *p=arg; + printk ("%s: frame_count=%d, h_size=%d, v_size=%d, " + "smpte_timecode=%d, picture_type=%d, " + "temporal_reference=%d, user_data=%s\n", s, + p->frame_count, p->h_size, + p->v_size, p->smpte_timecode, + p->picture_type, p->temporal_reference, + p->user_data); + break; + } + case VIDIOCKEY: + { + struct video_key *p=arg; + printk ("%s: key=%s, flags=%d\n", s, + p->key, p->flags); + break; + } + case VIDIOCGMBUF: + { + struct video_mbuf *p=arg; + printk ("%s: size=%d, frames=%d, offsets=0x%08lx\n", s, + p->size, + p->frames, + (unsigned long)p->offsets); + break; + } + case VIDIOCMCAPTURE: + { + struct video_mmap *p=arg; + printk ("%s: frame=%d, height=%d, width=%d, format=%d\n", s, + p->frame, + p->height, p->width, + p->format); + break; + } + case VIDIOCGPICT: + case VIDIOCSPICT: + case DECODER_SET_PICTURE: + { + struct video_picture *p=arg; + + printk ("%s: brightness=%d, hue=%d, colour=%d, contrast=%d," + " whiteness=%d, depth=%d, palette=%d\n", s, + p->brightness, p->hue, p->colour, + p->contrast, p->whiteness, p->depth, + p->palette); + break; + } + case VIDIOCSPLAYMODE: + { + struct video_play_mode *p=arg; + printk ("%s: mode=%d, p1=%d, p2=%d\n", s, + p->mode,p->p1,p->p2); + break; + } + case VIDIOCGTUNER: + case VIDIOCSTUNER: + { + struct video_tuner *p=arg; + printk ("%s: tuner=%d, name=%s, rangelow=%ld, rangehigh=%ld, " + "flags=%d, mode=%d, signal=%d\n", s, + p->tuner, p->name,p->rangelow, p->rangehigh, + p->flags,p->mode, p->signal); + break; + } + case VIDIOCGUNIT: + { + struct video_unit *p=arg; + printk ("%s: video=%d, vbi=%d, radio=%d, audio=%d, " + "teletext=%d\n", s, + p->video,p->vbi,p->radio,p->audio,p->teletext); + break; + } + case VIDIOCGWIN: + case VIDIOCSWIN: + { + struct video_window *p=arg; + printk ("%s: x=%d, y=%d, width=%d, height=%d, chromakey=%d," + " flags=%d, clipcount=%d\n", s, + p->x, p->y,p->width, p->height, + p->chromakey,p->flags, + p->clipcount); + break; + } + case VIDIOC_INT_AUDIO_CLOCK_FREQ: + case VIDIOC_INT_I2S_CLOCK_FREQ: + case VIDIOC_INT_S_STANDBY: + { + u32 *p=arg; + + printk ("%s: value=%d\n", s, *p); + break; + } + case VIDIOCGFREQ: + case VIDIOCSFREQ: + { + unsigned long *p=arg; + printk ("%s: value=%lu\n", s, *p); + break; + } + case VIDIOC_G_STD: + case VIDIOC_S_STD: + case VIDIOC_QUERYSTD: + { + v4l2_std_id *p=arg; + + printk ("%s: value=%llu\n", s, *p); + break; + } + } +} + /* ----------------------------------------------------------------- */ EXPORT_SYMBOL(v4l2_video_std_construct); @@ -376,6 +927,7 @@ EXPORT_SYMBOL(v4l2_prio_check); EXPORT_SYMBOL(v4l2_field_names); EXPORT_SYMBOL(v4l2_type_names); EXPORT_SYMBOL(v4l_printk_ioctl); +EXPORT_SYMBOL(v4l_printk_ioctl_arg); /* * Local variables: diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c index 0a4004a4393..caf3e7e2f21 100644 --- a/drivers/media/video/video-buf-dvb.c +++ b/drivers/media/video/video-buf-dvb.c @@ -96,7 +96,7 @@ static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed) if (!demux->dmx.frontend) return -EINVAL; - down(&dvb->lock); + mutex_lock(&dvb->lock); dvb->nfeeds++; rc = dvb->nfeeds; @@ -110,7 +110,7 @@ static int videobuf_dvb_start_feed(struct dvb_demux_feed *feed) } out: - up(&dvb->lock); + mutex_unlock(&dvb->lock); return rc; } @@ -120,14 +120,14 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed) struct videobuf_dvb *dvb = demux->priv; int err = 0; - down(&dvb->lock); + mutex_lock(&dvb->lock); dvb->nfeeds--; if (0 == dvb->nfeeds && NULL != dvb->thread) { // FIXME: cx8802_cancel_buffers(dev); err = kthread_stop(dvb->thread); dvb->thread = NULL; } - up(&dvb->lock); + mutex_unlock(&dvb->lock); return err; } @@ -139,7 +139,7 @@ int videobuf_dvb_register(struct videobuf_dvb *dvb, { int result; - init_MUTEX(&dvb->lock); + mutex_init(&dvb->lock); /* register adapter */ result = dvb_register_adapter(&dvb->adapter, dvb->name, module); diff --git a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c index 9ef477523d2..87e937581d5 100644 --- a/drivers/media/video/video-buf.c +++ b/drivers/media/video/video-buf.c @@ -59,8 +59,7 @@ videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages) pg = vmalloc_to_page(virt); if (NULL == pg) goto err; - if (PageHighMem(pg)) - BUG(); + BUG_ON(PageHighMem(pg)); sglist[i].page = pg; sglist[i].length = PAGE_SIZE; } @@ -385,7 +384,7 @@ void videobuf_queue_init(struct videobuf_queue* q, q->ops = ops; q->priv_data = priv; - init_MUTEX(&q->lock); + mutex_init(&q->lock); INIT_LIST_HEAD(&q->stream); } @@ -428,7 +427,7 @@ videobuf_queue_is_busy(struct videobuf_queue *q) void videobuf_queue_cancel(struct videobuf_queue *q) { - unsigned long flags; + unsigned long flags=0; int i; /* remove queued buffers from list */ @@ -549,7 +548,7 @@ videobuf_reqbufs(struct videobuf_queue *q, if (!list_empty(&q->stream)) return -EBUSY; - down(&q->lock); + mutex_lock(&q->lock); count = req->count; if (count > VIDEO_MAX_FRAME) count = VIDEO_MAX_FRAME; @@ -566,7 +565,7 @@ videobuf_reqbufs(struct videobuf_queue *q, req->count = count; done: - up(&q->lock); + mutex_unlock(&q->lock); return retval; } @@ -589,10 +588,10 @@ videobuf_qbuf(struct videobuf_queue *q, { struct videobuf_buffer *buf; enum v4l2_field field; - unsigned long flags; + unsigned long flags=0; int retval; - down(&q->lock); + mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) goto done; @@ -652,7 +651,7 @@ videobuf_qbuf(struct videobuf_queue *q, retval = 0; done: - up(&q->lock); + mutex_unlock(&q->lock); return retval; } @@ -663,7 +662,7 @@ videobuf_dqbuf(struct videobuf_queue *q, struct videobuf_buffer *buf; int retval; - down(&q->lock); + mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) goto done; @@ -693,7 +692,7 @@ videobuf_dqbuf(struct videobuf_queue *q, videobuf_status(b,buf,q->type); done: - up(&q->lock); + mutex_unlock(&q->lock); return retval; } @@ -701,10 +700,10 @@ int videobuf_streamon(struct videobuf_queue *q) { struct videobuf_buffer *buf; struct list_head *list; - unsigned long flags; + unsigned long flags=0; int retval; - down(&q->lock); + mutex_lock(&q->lock); retval = -EBUSY; if (q->reading) goto done; @@ -721,7 +720,7 @@ int videobuf_streamon(struct videobuf_queue *q) spin_unlock_irqrestore(q->irqlock,flags); done: - up(&q->lock); + mutex_unlock(&q->lock); return retval; } @@ -729,7 +728,7 @@ int videobuf_streamoff(struct videobuf_queue *q) { int retval = -EINVAL; - down(&q->lock); + mutex_lock(&q->lock); if (!q->streaming) goto done; videobuf_queue_cancel(q); @@ -737,7 +736,7 @@ int videobuf_streamoff(struct videobuf_queue *q) retval = 0; done: - up(&q->lock); + mutex_unlock(&q->lock); return retval; } @@ -746,7 +745,7 @@ videobuf_read_zerocopy(struct videobuf_queue *q, char __user *data, size_t count, loff_t *ppos) { enum v4l2_field field; - unsigned long flags; + unsigned long flags=0; int retval; /* setup stuff */ @@ -788,11 +787,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, int nonblocking) { enum v4l2_field field; - unsigned long flags; + unsigned long flags=0; unsigned size, nbufs, bytes; int retval; - down(&q->lock); + mutex_lock(&q->lock); nbufs = 1; size = 0; q->ops->buf_setup(q,&nbufs,&size); @@ -860,14 +859,14 @@ ssize_t videobuf_read_one(struct videobuf_queue *q, } done: - up(&q->lock); + mutex_unlock(&q->lock); return retval; } int videobuf_read_start(struct videobuf_queue *q) { enum v4l2_field field; - unsigned long flags; + unsigned long flags=0; int count = 0, size = 0; int err, i; @@ -919,10 +918,10 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, { unsigned int *fc, bytes; int err, retval; - unsigned long flags; + unsigned long flags=0; dprintk(2,"%s\n",__FUNCTION__); - down(&q->lock); + mutex_lock(&q->lock); retval = -EBUSY; if (q->streaming) goto done; @@ -996,7 +995,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q, } done: - up(&q->lock); + mutex_unlock(&q->lock); return retval; } @@ -1007,7 +1006,7 @@ unsigned int videobuf_poll_stream(struct file *file, struct videobuf_buffer *buf = NULL; unsigned int rc = 0; - down(&q->lock); + mutex_lock(&q->lock); if (q->streaming) { if (!list_empty(&q->stream)) buf = list_entry(q->stream.next, @@ -1035,7 +1034,7 @@ unsigned int videobuf_poll_stream(struct file *file, buf->state == STATE_ERROR) rc = POLLIN|POLLRDNORM; } - up(&q->lock); + mutex_unlock(&q->lock); return rc; } @@ -1064,7 +1063,7 @@ videobuf_vm_close(struct vm_area_struct *vma) map->count--; if (0 == map->count) { dprintk(1,"munmap %p q=%p\n",map,q); - down(&q->lock); + mutex_lock(&q->lock); for (i = 0; i < VIDEO_MAX_FRAME; i++) { if (NULL == q->bufs[i]) continue; @@ -1076,7 +1075,7 @@ videobuf_vm_close(struct vm_area_struct *vma) q->bufs[i]->baddr = 0; q->ops->buf_release(q,q->bufs[i]); } - up(&q->lock); + mutex_unlock(&q->lock); kfree(map); } return; @@ -1170,7 +1169,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, unsigned int first,last,size,i; int retval; - down(&q->lock); + mutex_lock(&q->lock); retval = -EINVAL; if (!(vma->vm_flags & VM_WRITE)) { dprintk(1,"mmap app bug: PROT_WRITE please\n"); @@ -1238,7 +1237,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, retval = 0; done: - up(&q->lock); + mutex_unlock(&q->lock); return retval; } diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c index 078880e4c8c..75e3d41382f 100644 --- a/drivers/media/video/videodev.c +++ b/drivers/media/video/videodev.c @@ -224,13 +224,13 @@ int video_exclusive_open(struct inode *inode, struct file *file) struct video_device *vfl = video_devdata(file); int retval = 0; - down(&vfl->lock); + mutex_lock(&vfl->lock); if (vfl->users) { retval = -EBUSY; } else { vfl->users++; } - up(&vfl->lock); + mutex_unlock(&vfl->lock); return retval; } @@ -279,23 +279,23 @@ int video_register_device(struct video_device *vfd, int type, int nr) switch(type) { case VFL_TYPE_GRABBER: - base=0; - end=64; + base=MINOR_VFL_TYPE_GRABBER_MIN; + end=MINOR_VFL_TYPE_GRABBER_MAX+1; name_base = "video"; break; case VFL_TYPE_VTX: - base=192; - end=224; + base=MINOR_VFL_TYPE_VTX_MIN; + end=MINOR_VFL_TYPE_VTX_MAX+1; name_base = "vtx"; break; case VFL_TYPE_VBI: - base=224; - end=256; + base=MINOR_VFL_TYPE_VBI_MIN; + end=MINOR_VFL_TYPE_VBI_MAX+1; name_base = "vbi"; break; case VFL_TYPE_RADIO: - base=64; - end=128; + base=MINOR_VFL_TYPE_RADIO_MIN; + end=MINOR_VFL_TYPE_RADIO_MAX+1; name_base = "radio"; break; default: @@ -328,7 +328,7 @@ int video_register_device(struct video_device *vfd, int type, int nr) sprintf(vfd->devfs_name, "v4l/%s%d", name_base, i - base); devfs_mk_cdev(MKDEV(VIDEO_MAJOR, vfd->minor), S_IFCHR | S_IRUSR | S_IWUSR, vfd->devfs_name); - init_MUTEX(&vfd->lock); + mutex_init(&vfd->lock); /* sysfs class */ memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c index c8fd8238904..0229819d0aa 100644 --- a/drivers/media/video/vino.c +++ b/drivers/media/video/vino.c @@ -42,6 +42,7 @@ #include <linux/videodev.h> #include <linux/videodev2.h> #include <linux/video_decoder.h> +#include <linux/mutex.h> #include <asm/paccess.h> #include <asm/io.h> @@ -245,7 +246,7 @@ struct vino_framebuffer_queue { struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX]; spinlock_t queue_lock; - struct semaphore queue_sem; + struct mutex queue_mutex; wait_queue_head_t frame_wait_queue; }; @@ -283,7 +284,7 @@ struct vino_channel_settings { /* the driver is currently processing the queue */ int capturing; - struct semaphore sem; + struct mutex mutex; spinlock_t capture_lock; unsigned int users; @@ -1131,11 +1132,11 @@ static void vino_queue_free(struct vino_framebuffer_queue *q) if (q->type != VINO_MEMORY_MMAP) return; - down(&q->queue_sem); + mutex_lock(&q->queue_mutex); vino_queue_free_with_count(q, q->length); - up(&q->queue_sem); + mutex_unlock(&q->queue_mutex); } static int vino_queue_init(struct vino_framebuffer_queue *q, @@ -1159,7 +1160,7 @@ static int vino_queue_init(struct vino_framebuffer_queue *q, if (*length < 1) return -EINVAL; - down(&q->queue_sem); + mutex_lock(&q->queue_mutex); if (*length > VINO_FRAMEBUFFER_COUNT_MAX) *length = VINO_FRAMEBUFFER_COUNT_MAX; @@ -1211,7 +1212,7 @@ static int vino_queue_init(struct vino_framebuffer_queue *q, q->magic = VINO_QUEUE_MAGIC; } - up(&q->queue_sem); + mutex_unlock(&q->queue_mutex); return ret; } @@ -4045,7 +4046,7 @@ static int vino_open(struct inode *inode, struct file *file) dprintk("open(): channel = %c\n", (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B'); - down(&vcs->sem); + mutex_lock(&vcs->mutex); if (vcs->users) { dprintk("open(): driver busy\n"); @@ -4062,7 +4063,7 @@ static int vino_open(struct inode *inode, struct file *file) vcs->users++; out: - up(&vcs->sem); + mutex_unlock(&vcs->mutex); dprintk("open(): %s!\n", ret ? "failed" : "complete"); @@ -4075,7 +4076,7 @@ static int vino_close(struct inode *inode, struct file *file) struct vino_channel_settings *vcs = video_get_drvdata(dev); dprintk("close():\n"); - down(&vcs->sem); + mutex_lock(&vcs->mutex); vcs->users--; @@ -4087,7 +4088,7 @@ static int vino_close(struct inode *inode, struct file *file) vino_queue_free(&vcs->fb_queue); } - up(&vcs->sem); + mutex_unlock(&vcs->mutex); return 0; } @@ -4130,7 +4131,7 @@ static int vino_mmap(struct file *file, struct vm_area_struct *vma) // TODO: reject mmap if already mapped - if (down_interruptible(&vcs->sem)) + if (mutex_lock_interruptible(&vcs->mutex)) return -EINTR; if (vcs->reading) { @@ -4214,7 +4215,7 @@ found: vma->vm_ops = &vino_vm_ops; out: - up(&vcs->sem); + mutex_unlock(&vcs->mutex); return ret; } @@ -4374,12 +4375,12 @@ static int vino_ioctl(struct inode *inode, struct file *file, struct vino_channel_settings *vcs = video_get_drvdata(dev); int ret; - if (down_interruptible(&vcs->sem)) + if (mutex_lock_interruptible(&vcs->mutex)) return -EINTR; ret = video_usercopy(inode, file, cmd, arg, vino_do_ioctl); - up(&vcs->sem); + mutex_unlock(&vcs->mutex); return ret; } @@ -4564,10 +4565,10 @@ static int vino_init_channel_settings(struct vino_channel_settings *vcs, vcs->capturing = 0; - init_MUTEX(&vcs->sem); + mutex_init(&vcs->mutex); spin_lock_init(&vcs->capture_lock); - init_MUTEX(&vcs->fb_queue.queue_sem); + mutex_init(&vcs->fb_queue.queue_mutex); spin_lock_init(&vcs->fb_queue.queue_lock); init_waitqueue_head(&vcs->fb_queue.frame_wait_queue); |