diff options
author | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-08-22 10:34:29 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-08-22 10:34:29 -0300 |
commit | 4d3f684d3b6ab28ec9e251fff156d0b0f53d0517 (patch) | |
tree | f82a2ae2dc042d6d1de61f62babeb8c5f28b22a1 /linux/drivers/media | |
parent | 87eb1f67e4981f3a09825012f16af0107a7adb45 (diff) | |
parent | b5ff2cd5cc913156858a0b15a186144f146c89d7 (diff) | |
download | mediapointer-dvb-s2-4d3f684d3b6ab28ec9e251fff156d0b0f53d0517.tar.gz mediapointer-dvb-s2-4d3f684d3b6ab28ec9e251fff156d0b0f53d0517.tar.bz2 |
merge: http://linuxtv.org/hg/~mkrufky/sms1xxx
From: Mauro Carvalho Chehab <mchehab@infradead.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'linux/drivers/media')
216 files changed, 9585 insertions, 8726 deletions
diff --git a/linux/drivers/media/common/ir-keymaps.c b/linux/drivers/media/common/ir-keymaps.c index a464ad34e..f1d172a3f 100644 --- a/linux/drivers/media/common/ir-keymaps.c +++ b/linux/drivers/media/common/ir-keymaps.c @@ -1842,12 +1842,61 @@ IR_KEYTAB_TYPE ir_codes_encore_enltv[IR_KEYTAB_SIZE] = { [ 0x41 ] = KEY_GREEN, /* AP2 */ [ 0x47 ] = KEY_YELLOW, /* AP3 */ [ 0x57 ] = KEY_BLUE, /* AP4 */ - - }; - EXPORT_SYMBOL_GPL(ir_codes_encore_enltv); +/* Encore ENLTV2-FM - silver plastic - "Wand Media" written at the botton + Mauro Carvalho Chehab <mchehab@infradead.org> */ +IR_KEYTAB_TYPE ir_codes_encore_enltv2[IR_KEYTAB_SIZE] = { + [0x4c] = KEY_POWER2, + [0x4a] = KEY_TUNER, + [0x40] = KEY_1, + [0x60] = KEY_2, + [0x50] = KEY_3, + [0x70] = KEY_4, + [0x48] = KEY_5, + [0x68] = KEY_6, + [0x58] = KEY_7, + [0x78] = KEY_8, + [0x44] = KEY_9, + [0x54] = KEY_0, + + [0x64] = KEY_LAST, /* +100 */ + [0x4e] = KEY_AGAIN, /* Recall */ + + [0x6c] = KEY_SWITCHVIDEOMODE, /* Video Source */ + [0x5e] = KEY_MENU, + [0x56] = KEY_SCREEN, + [0x7a] = KEY_SETUP, + + [0x46] = KEY_MUTE, + [0x5c] = KEY_MODE, /* Stereo */ + [0x74] = KEY_INFO, + [0x7c] = KEY_CLEAR, + + [0x55] = KEY_UP, + [0x49] = KEY_DOWN, + [0x7e] = KEY_LEFT, + [0x59] = KEY_RIGHT, + [0x6a] = KEY_ENTER, + + [0x42] = KEY_VOLUMEUP, + [0x62] = KEY_VOLUMEDOWN, + [0x52] = KEY_CHANNELUP, + [0x72] = KEY_CHANNELDOWN, + + [0x41] = KEY_RECORD, + [0x51] = KEY_SHUFFLE, /* Snapshot */ + [0x75] = KEY_TIME, /* Timeshift */ + [0x71] = KEY_TV2, /* PIP */ + + [0x45] = KEY_REWIND, + [0x6f] = KEY_PAUSE, + [0x7d] = KEY_FORWARD, + [0x79] = KEY_STOP, +}; +EXPORT_SYMBOL_GPL(ir_codes_encore_enltv2); + /* for the Technotrend 1500 bundled remotes (grey and black): */ IR_KEYTAB_TYPE ir_codes_tt_1500[IR_KEYTAB_SIZE] = { [ 0x01 ] = KEY_POWER, diff --git a/linux/drivers/media/common/saa7146_fops.c b/linux/drivers/media/common/saa7146_fops.c index ac035cbcf..a3dafa4fe 100644 --- a/linux/drivers/media/common/saa7146_fops.c +++ b/linux/drivers/media/common/saa7146_fops.c @@ -564,7 +564,7 @@ int saa7146_unregister_device(struct video_device **vid, struct saa7146_dev* dev DEB_EE(("dev:%p\n",dev)); - if( VFL_TYPE_GRABBER == (*vid)->type ) { + if ((*vid)->vfl_type == VFL_TYPE_GRABBER) { vv->video_minor = -1; } else { vv->vbi_minor = -1; diff --git a/linux/drivers/media/common/saa7146_video.c b/linux/drivers/media/common/saa7146_video.c index d3185e610..1c22c39c2 100644 --- a/linux/drivers/media/common/saa7146_video.c +++ b/linux/drivers/media/common/saa7146_video.c @@ -657,7 +657,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu /* if we have a user buffer, the first page may not be aligned to a page boundary. */ - pt1->offset = list->offset; + pt1->offset = dma->sglist->offset; pt2->offset = pt1->offset+o1; pt3->offset = pt1->offset+o2; @@ -959,21 +959,18 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; - int index; switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OVERLAY: { - index = f->index; - if (index < 0 || index >= NUM_FORMATS) { + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + if (f->index >= NUM_FORMATS) return -EINVAL; - } - memset(f,0,sizeof(*f)); - f->index = index; - strlcpy((char *)f->description,formats[index].name,sizeof(f->description)); - f->pixelformat = formats[index].pixelformat; + strlcpy((char *)f->description, formats[f->index].name, + sizeof(f->description)); + f->pixelformat = formats[f->index].pixelformat; + f->flags = 0; + memset(f->reserved, 0, sizeof(f->reserved)); break; - } default: return -EINVAL; } diff --git a/linux/drivers/media/common/tuners/Kconfig b/linux/drivers/media/common/tuners/Kconfig index 850d5689b..6f92beaa5 100644 --- a/linux/drivers/media/common/tuners/Kconfig +++ b/linux/drivers/media/common/tuners/Kconfig @@ -21,9 +21,8 @@ config MEDIA_TUNER tristate default VIDEO_MEDIA && I2C depends on VIDEO_MEDIA && I2C - select FW_LOADER if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG - select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG - select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE && HOTPLUG + select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMIZE + select MEDIA_TUNER_XC5000 if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_MT20XX if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_TDA8290 if !MEDIA_TUNER_CUSTOMIZE select MEDIA_TUNER_TEA5761 if !MEDIA_TUNER_CUSTOMIZE @@ -138,8 +137,6 @@ config MEDIA_TUNER_QT1010 config MEDIA_TUNER_XC2028 tristate "XCeive xc2028/xc3028 tuners" depends on VIDEO_MEDIA && I2C - depends on HOTPLUG - select FW_LOADER default m if MEDIA_TUNER_CUSTOMIZE help Say Y here to include support for the xc2028/xc3028 tuners. @@ -147,8 +144,6 @@ config MEDIA_TUNER_XC2028 config MEDIA_TUNER_XC5000 tristate "Xceive XC5000 silicon tuner" depends on VIDEO_MEDIA && I2C - depends on HOTPLUG - select FW_LOADER default m if DVB_FE_CUSTOMISE help A driver for the silicon tuner XC5000 from Xceive. @@ -162,4 +157,11 @@ config MEDIA_TUNER_MXL5005S help A driver for the silicon tuner MXL5005S from MaxLinear. +config MEDIA_TUNER_MXL5007T + tristate "MaxLinear MxL5007T silicon tuner" + depends on VIDEO_MEDIA && I2C + default m if DVB_FE_CUSTOMISE + help + A driver for the silicon tuner MxL5007T from MaxLinear. + endif # MEDIA_TUNER_CUSTOMIZE diff --git a/linux/drivers/media/common/tuners/Makefile b/linux/drivers/media/common/tuners/Makefile index 55f7e6706..4dfbe5b82 100644 --- a/linux/drivers/media/common/tuners/Makefile +++ b/linux/drivers/media/common/tuners/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o +obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core EXTRA_CFLAGS += -Idrivers/media/dvb/frontends diff --git a/linux/drivers/media/common/tuners/mt20xx.c b/linux/drivers/media/common/tuners/mt20xx.c index 9d9f1cf11..2669cd0bf 100644 --- a/linux/drivers/media/common/tuners/mt20xx.c +++ b/linux/drivers/media/common/tuners/mt20xx.c @@ -149,7 +149,8 @@ static int mt2032_compute_freq(struct dvb_frontend *fe, tuner_dbg("mt2032: rfin=%d lo2=%d lo2n=%d lo2a=%d num=%d lo2freq=%d\n", rfin,lo2,lo2n,lo2a,lo2num,lo2freq); - if(lo1a<0 || lo1a>7 || lo1n<17 ||lo1n>48 || lo2a<0 ||lo2a >7 ||lo2n<17 || lo2n>30) { + if (lo1a > 7 || lo1n < 17 || lo1n > 48 || lo2a > 7 || lo2n < 17 || + lo2n > 30) { tuner_info("mt2032: frequency parameters out of range: %d %d %d %d\n", lo1a, lo1n, lo2a,lo2n); return(-1); diff --git a/linux/drivers/media/common/tuners/mxl5007t.c b/linux/drivers/media/common/tuners/mxl5007t.c new file mode 100644 index 000000000..e795650c2 --- /dev/null +++ b/linux/drivers/media/common/tuners/mxl5007t.c @@ -0,0 +1,1052 @@ +/* + * mxl5007t.c - driver for the MaxLinear MxL5007T silicon tuner + * + * Copyright (C) 2008 Michael Krufky <mkrufky@linuxtv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/i2c.h> +#include <linux/types.h> +#include "compat.h" +#include <linux/videodev2.h> +#include "tuner-i2c.h" +#include "mxl5007t.h" + +static DEFINE_MUTEX(mxl5007t_list_mutex); +static LIST_HEAD(hybrid_tuner_instance_list); + +static int mxl5007t_debug; +module_param_named(debug, mxl5007t_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debug level"); + +/* ------------------------------------------------------------------------- */ + +#define mxl_printk(kern, fmt, arg...) \ + printk(kern "%s: " fmt "\n", __func__, ##arg) + +#define mxl_err(fmt, arg...) \ + mxl_printk(KERN_ERR, "%d: " fmt, __LINE__, ##arg) + +#define mxl_warn(fmt, arg...) \ + mxl_printk(KERN_WARNING, fmt, ##arg) + +#define mxl_info(fmt, arg...) \ + mxl_printk(KERN_INFO, fmt, ##arg) + +#define mxl_debug(fmt, arg...) \ +({ \ + if (mxl5007t_debug) \ + mxl_printk(KERN_DEBUG, fmt, ##arg); \ +}) + +#define mxl_fail(ret) \ +({ \ + int __ret; \ + __ret = (ret < 0); \ + if (__ret) \ + mxl_printk(KERN_ERR, "error %d on line %d", \ + ret, __LINE__); \ + __ret; \ +}) + +/* ------------------------------------------------------------------------- */ + +#define MHz 1000000 + +enum mxl5007t_mode { + MxL_MODE_OTA_DVBT_ATSC = 0, + MxL_MODE_OTA_NTSC_PAL_GH = 1, + MxL_MODE_OTA_PAL_IB = 2, + MxL_MODE_OTA_PAL_D_SECAM_KL = 3, + MxL_MODE_OTA_ISDBT = 4, + MxL_MODE_CABLE_DIGITAL = 0x10, + MxL_MODE_CABLE_NTSC_PAL_GH = 0x11, + MxL_MODE_CABLE_PAL_IB = 0x12, + MxL_MODE_CABLE_PAL_D_SECAM_KL = 0x13, + MxL_MODE_CABLE_SCTE40 = 0x14, +}; + +enum mxl5007t_chip_version { + MxL_UNKNOWN_ID = 0x00, + MxL_5007_V1_F1 = 0x11, + MxL_5007_V1_F2 = 0x12, + MxL_5007_V2_100_F1 = 0x21, + MxL_5007_V2_100_F2 = 0x22, + MxL_5007_V2_200_F1 = 0x23, + MxL_5007_V2_200_F2 = 0x24, +}; + +struct reg_pair_t { + u8 reg; + u8 val; +}; + +/* ------------------------------------------------------------------------- */ + +static struct reg_pair_t init_tab[] = { + { 0x0b, 0x44 }, /* XTAL */ + { 0x0c, 0x60 }, /* IF */ + { 0x10, 0x00 }, /* MISC */ + { 0x12, 0xca }, /* IDAC */ + { 0x16, 0x90 }, /* MODE */ + { 0x32, 0x38 }, /* MODE Analog/Digital */ + { 0xd8, 0x18 }, /* CLK_OUT_ENABLE */ + { 0x2c, 0x34 }, /* OVERRIDE */ + { 0x4d, 0x40 }, /* OVERRIDE */ + { 0x7f, 0x02 }, /* OVERRIDE */ + { 0x9a, 0x52 }, /* OVERRIDE */ + { 0x48, 0x5a }, /* OVERRIDE */ + { 0x76, 0x1a }, /* OVERRIDE */ + { 0x6a, 0x48 }, /* OVERRIDE */ + { 0x64, 0x28 }, /* OVERRIDE */ + { 0x66, 0xe6 }, /* OVERRIDE */ + { 0x35, 0x0e }, /* OVERRIDE */ + { 0x7e, 0x01 }, /* OVERRIDE */ + { 0x83, 0x00 }, /* OVERRIDE */ + { 0x04, 0x0b }, /* OVERRIDE */ + { 0x05, 0x01 }, /* TOP_MASTER_ENABLE */ + { 0, 0 } +}; + +static struct reg_pair_t init_tab_cable[] = { + { 0x0b, 0x44 }, /* XTAL */ + { 0x0c, 0x60 }, /* IF */ + { 0x10, 0x00 }, /* MISC */ + { 0x12, 0xca }, /* IDAC */ + { 0x16, 0x90 }, /* MODE */ + { 0x32, 0x38 }, /* MODE A/D */ + { 0x71, 0x3f }, /* TOP1 */ + { 0x72, 0x3f }, /* TOP2 */ + { 0x74, 0x3f }, /* TOP3 */ + { 0xd8, 0x18 }, /* CLK_OUT_ENABLE */ + { 0x2c, 0x34 }, /* OVERRIDE */ + { 0x4d, 0x40 }, /* OVERRIDE */ + { 0x7f, 0x02 }, /* OVERRIDE */ + { 0x9a, 0x52 }, /* OVERRIDE */ + { 0x48, 0x5a }, /* OVERRIDE */ + { 0x76, 0x1a }, /* OVERRIDE */ + { 0x6a, 0x48 }, /* OVERRIDE */ + { 0x64, 0x28 }, /* OVERRIDE */ + { 0x66, 0xe6 }, /* OVERRIDE */ + { 0x35, 0x0e }, /* OVERRIDE */ + { 0x7e, 0x01 }, /* OVERRIDE */ + { 0x04, 0x0b }, /* OVERRIDE */ + { 0x68, 0xb4 }, /* OVERRIDE */ + { 0x36, 0x00 }, /* OVERRIDE */ + { 0x05, 0x01 }, /* TOP_MASTER_ENABLE */ + { 0, 0 } +}; + +/* ------------------------------------------------------------------------- */ + +static struct reg_pair_t reg_pair_rftune[] = { + { 0x11, 0x00 }, /* abort tune */ + { 0x13, 0x15 }, + { 0x14, 0x40 }, + { 0x15, 0x0e }, + { 0x11, 0x02 }, /* start tune */ + { 0, 0 } +}; + +/* ------------------------------------------------------------------------- */ + +struct mxl5007t_state { + struct list_head hybrid_tuner_instance_list; + struct tuner_i2c_props i2c_props; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) + struct mutex lock; +#else + struct semaphore lock; +#endif + + struct mxl5007t_config *config; + + enum mxl5007t_chip_version chip_id; + + struct reg_pair_t tab_init[ARRAY_SIZE(init_tab)]; + struct reg_pair_t tab_init_cable[ARRAY_SIZE(init_tab_cable)]; + struct reg_pair_t tab_rftune[ARRAY_SIZE(reg_pair_rftune)]; + + u32 frequency; + u32 bandwidth; +}; + +/* ------------------------------------------------------------------------- */ + +/* called by _init and _rftun to manipulate the register arrays */ + +static void set_reg_bits(struct reg_pair_t *reg_pair, u8 reg, u8 mask, u8 val) +{ + unsigned int i = 0; + + while (reg_pair[i].reg || reg_pair[i].val) { + if (reg_pair[i].reg == reg) { + reg_pair[i].val &= ~mask; + reg_pair[i].val |= val; + } + i++; + + } + return; +} + +static void copy_reg_bits(struct reg_pair_t *reg_pair1, + struct reg_pair_t *reg_pair2) +{ + unsigned int i, j; + + i = j = 0; + + while (reg_pair1[i].reg || reg_pair1[i].val) { + while (reg_pair2[j].reg || reg_pair2[j].reg) { + if (reg_pair1[i].reg != reg_pair2[j].reg) { + j++; + continue; + } + reg_pair2[j].val = reg_pair1[i].val; + break; + } + i++; + } + return; +} + +/* ------------------------------------------------------------------------- */ + +static void mxl5007t_set_mode_bits(struct mxl5007t_state *state, + enum mxl5007t_mode mode, + s32 if_diff_out_level) +{ + switch (mode) { + case MxL_MODE_OTA_DVBT_ATSC: + set_reg_bits(state->tab_init, 0x32, 0x0f, 0x06); + set_reg_bits(state->tab_init, 0x35, 0xff, 0x0e); + break; + case MxL_MODE_OTA_ISDBT: + set_reg_bits(state->tab_init, 0x32, 0x0f, 0x06); + set_reg_bits(state->tab_init, 0x35, 0xff, 0x12); + break; + case MxL_MODE_OTA_NTSC_PAL_GH: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x00); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + break; + case MxL_MODE_OTA_PAL_IB: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x10); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + break; + case MxL_MODE_OTA_PAL_D_SECAM_KL: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x20); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + break; + case MxL_MODE_CABLE_DIGITAL: + set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01); + set_reg_bits(state->tab_init_cable, 0x72, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17); + break; + case MxL_MODE_CABLE_NTSC_PAL_GH: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x00); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01); + set_reg_bits(state->tab_init_cable, 0x72, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17); + break; + case MxL_MODE_CABLE_PAL_IB: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x10); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01); + set_reg_bits(state->tab_init_cable, 0x72, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17); + break; + case MxL_MODE_CABLE_PAL_D_SECAM_KL: + set_reg_bits(state->tab_init, 0x16, 0x70, 0x20); + set_reg_bits(state->tab_init, 0x32, 0xff, 0x85); + set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01); + set_reg_bits(state->tab_init_cable, 0x72, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17); + break; + case MxL_MODE_CABLE_SCTE40: + set_reg_bits(state->tab_init_cable, 0x36, 0xff, 0x08); + set_reg_bits(state->tab_init_cable, 0x68, 0xff, 0xbc); + set_reg_bits(state->tab_init_cable, 0x71, 0xff, 0x01); + set_reg_bits(state->tab_init_cable, 0x72, 0xff, + 8 - if_diff_out_level); + set_reg_bits(state->tab_init_cable, 0x74, 0xff, 0x17); + break; + default: + mxl_fail(-EINVAL); + } + return; +} + +static void mxl5007t_set_if_freq_bits(struct mxl5007t_state *state, + enum mxl5007t_if_freq if_freq, + int invert_if) +{ + u8 val; + + switch (if_freq) { + case MxL_IF_4_MHZ: + val = 0x00; + break; + case MxL_IF_4_5_MHZ: + val = 0x20; + break; + case MxL_IF_4_57_MHZ: + val = 0x30; + break; + case MxL_IF_5_MHZ: + val = 0x40; + break; + case MxL_IF_5_38_MHZ: + val = 0x50; + break; + case MxL_IF_6_MHZ: + val = 0x60; + break; + case MxL_IF_6_28_MHZ: + val = 0x70; + break; + case MxL_IF_9_1915_MHZ: + val = 0x80; + break; + case MxL_IF_35_25_MHZ: + val = 0x90; + break; + case MxL_IF_36_15_MHZ: + val = 0xa0; + break; + case MxL_IF_44_MHZ: + val = 0xb0; + break; + default: + mxl_fail(-EINVAL); + return; + } + set_reg_bits(state->tab_init, 0x0c, 0xf0, val); + + /* set inverted IF or normal IF */ + set_reg_bits(state->tab_init, 0x0c, 0x08, invert_if ? 0x08 : 0x00); + + return; +} + +static void mxl5007t_set_xtal_freq_bits(struct mxl5007t_state *state, + enum mxl5007t_xtal_freq xtal_freq) +{ + u8 val; + + switch (xtal_freq) { + case MxL_XTAL_16_MHZ: + val = 0x00; /* select xtal freq & Ref Freq */ + break; + case MxL_XTAL_20_MHZ: + val = 0x11; + break; + case MxL_XTAL_20_25_MHZ: + val = 0x22; + break; + case MxL_XTAL_20_48_MHZ: + val = 0x33; + break; + case MxL_XTAL_24_MHZ: + val = 0x44; + break; + case MxL_XTAL_25_MHZ: + val = 0x55; + break; + case MxL_XTAL_25_14_MHZ: + val = 0x66; + break; + case MxL_XTAL_27_MHZ: + val = 0x77; + break; + case MxL_XTAL_28_8_MHZ: + val = 0x88; + break; + case MxL_XTAL_32_MHZ: + val = 0x99; + break; + case MxL_XTAL_40_MHZ: + val = 0xaa; + break; + case MxL_XTAL_44_MHZ: + val = 0xbb; + break; + case MxL_XTAL_48_MHZ: + val = 0xcc; + break; + case MxL_XTAL_49_3811_MHZ: + val = 0xdd; + break; + default: + mxl_fail(-EINVAL); + return; + } + set_reg_bits(state->tab_init, 0x0b, 0xff, val); + + return; +} + +static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state, + enum mxl5007t_mode mode) +{ + struct mxl5007t_config *cfg = state->config; + + memcpy(&state->tab_init, &init_tab, sizeof(init_tab)); + memcpy(&state->tab_init_cable, &init_tab_cable, sizeof(init_tab_cable)); + + mxl5007t_set_mode_bits(state, mode, cfg->if_diff_out_level); + mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if); + mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz); + + set_reg_bits(state->tab_init, 0x10, 0x40, cfg->loop_thru_enable << 6); + + set_reg_bits(state->tab_init, 0xd8, 0x08, cfg->clk_out_enable << 3); + + set_reg_bits(state->tab_init, 0x10, 0x07, cfg->clk_out_amp); + + /* set IDAC to automatic mode control by AGC */ + set_reg_bits(state->tab_init, 0x12, 0x80, 0x00); + + if (mode >= MxL_MODE_CABLE_DIGITAL) { + copy_reg_bits(state->tab_init, state->tab_init_cable); + return state->tab_init_cable; + } else + return state->tab_init; +} + +/* ------------------------------------------------------------------------- */ + +enum mxl5007t_bw_mhz { + MxL_BW_6MHz = 6, + MxL_BW_7MHz = 7, + MxL_BW_8MHz = 8, +}; + +static void mxl5007t_set_bw_bits(struct mxl5007t_state *state, + enum mxl5007t_bw_mhz bw) +{ + u8 val; + + switch (bw) { + case MxL_BW_6MHz: + val = 0x15; /* set DIG_MODEINDEX, DIG_MODEINDEX_A, + * and DIG_MODEINDEX_CSF */ + break; + case MxL_BW_7MHz: + val = 0x21; + break; + case MxL_BW_8MHz: + val = 0x3f; + break; + default: + mxl_fail(-EINVAL); + return; + } + set_reg_bits(state->tab_rftune, 0x13, 0x3f, val); + + return; +} + +static struct +reg_pair_t *mxl5007t_calc_rf_tune_regs(struct mxl5007t_state *state, + u32 rf_freq, enum mxl5007t_bw_mhz bw) +{ + u32 dig_rf_freq = 0; + u32 temp; + u32 frac_divider = 1000000; + unsigned int i; + + memcpy(&state->tab_rftune, ®_pair_rftune, sizeof(reg_pair_rftune)); + + mxl5007t_set_bw_bits(state, bw); + + /* Convert RF frequency into 16 bits => + * 10 bit integer (MHz) + 6 bit fraction */ + dig_rf_freq = rf_freq / MHz; + + temp = rf_freq % MHz; + + for (i = 0; i < 6; i++) { + dig_rf_freq <<= 1; + frac_divider /= 2; + if (temp > frac_divider) { + temp -= frac_divider; + dig_rf_freq++; + } + } + + /* add to have shift center point by 7.8124 kHz */ + if (temp > 7812) + dig_rf_freq++; + + set_reg_bits(state->tab_rftune, 0x14, 0xff, (u8)dig_rf_freq); + set_reg_bits(state->tab_rftune, 0x15, 0xff, (u8)(dig_rf_freq >> 8)); + + return state->tab_rftune; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_write_reg(struct mxl5007t_state *state, u8 reg, u8 val) +{ + u8 buf[] = { reg, val }; + struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, + .buf = buf, .len = 2 }; + int ret; + + ret = i2c_transfer(state->i2c_props.adap, &msg, 1); + if (ret != 1) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_write_regs(struct mxl5007t_state *state, + struct reg_pair_t *reg_pair) +{ + unsigned int i = 0; + int ret = 0; + + while ((ret == 0) && (reg_pair[i].reg || reg_pair[i].val)) { + ret = mxl5007t_write_reg(state, + reg_pair[i].reg, reg_pair[i].val); + i++; + } + return ret; +} + +static int mxl5007t_read_reg(struct mxl5007t_state *state, u8 reg, u8 *val) +{ + struct i2c_msg msg[] = { + { .addr = state->i2c_props.addr, .flags = 0, + .buf = ®, .len = 1 }, + { .addr = state->i2c_props.addr, .flags = I2C_M_RD, + .buf = val, .len = 1 }, + }; + int ret; + + ret = i2c_transfer(state->i2c_props.adap, msg, 2); + if (ret != 2) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_soft_reset(struct mxl5007t_state *state) +{ + u8 d = 0xff; + struct i2c_msg msg = { .addr = state->i2c_props.addr, .flags = 0, + .buf = &d, .len = 1 }; + + int ret = i2c_transfer(state->i2c_props.adap, &msg, 1); + + if (ret != 1) { + mxl_err("failed!"); + return -EREMOTEIO; + } + return 0; +} + +static int mxl5007t_tuner_init(struct mxl5007t_state *state, + enum mxl5007t_mode mode) +{ + struct reg_pair_t *init_regs; + int ret; + + ret = mxl5007t_soft_reset(state); + if (mxl_fail(ret)) + goto fail; + + /* calculate initialization reg array */ + init_regs = mxl5007t_calc_init_regs(state, mode); + + ret = mxl5007t_write_regs(state, init_regs); + if (mxl_fail(ret)) + goto fail; + mdelay(1); + + ret = mxl5007t_write_reg(state, 0x2c, 0x35); + mxl_fail(ret); +fail: + return ret; +} + +static int mxl5007t_tuner_rf_tune(struct mxl5007t_state *state, u32 rf_freq_hz, + enum mxl5007t_bw_mhz bw) +{ + struct reg_pair_t *rf_tune_regs; + int ret; + + /* calculate channel change reg array */ + rf_tune_regs = mxl5007t_calc_rf_tune_regs(state, rf_freq_hz, bw); + + ret = mxl5007t_write_regs(state, rf_tune_regs); + if (mxl_fail(ret)) + goto fail; + msleep(3); +fail: + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_synth_lock_status(struct mxl5007t_state *state, + int *rf_locked, int *ref_locked) +{ + u8 d; + int ret; + + *rf_locked = 0; + *ref_locked = 0; + + ret = mxl5007t_read_reg(state, 0xcf, &d); + if (mxl_fail(ret)) + goto fail; + + if ((d & 0x0c) == 0x0c) + *rf_locked = 1; + + if ((d & 0x03) == 0x03) + *ref_locked = 1; +fail: + return ret; +} + +static int mxl5007t_check_rf_input_power(struct mxl5007t_state *state, + s32 *rf_input_level) +{ + u8 d1, d2; + int ret; + + ret = mxl5007t_read_reg(state, 0xb7, &d1); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_read_reg(state, 0xbf, &d2); + if (mxl_fail(ret)) + goto fail; + + d2 = d2 >> 4; + if (d2 > 7) + d2 += 0xf0; + + *rf_input_level = (s32)(d1 + d2 - 113); +fail: + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_get_status(struct dvb_frontend *fe, u32 *status) +{ + struct mxl5007t_state *state = fe->tuner_priv; + int rf_locked, ref_locked; + s32 rf_input_level; + int ret; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_synth_lock_status(state, &rf_locked, &ref_locked); + if (mxl_fail(ret)) + goto fail; + mxl_debug("%s%s", rf_locked ? "rf locked " : "", + ref_locked ? "ref locked" : ""); + + ret = mxl5007t_check_rf_input_power(state, &rf_input_level); + if (mxl_fail(ret)) + goto fail; + mxl_debug("rf input power: %d", rf_input_level); +fail: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) +{ + struct mxl5007t_state *state = fe->tuner_priv; + enum mxl5007t_bw_mhz bw; + enum mxl5007t_mode mode; + int ret; + u32 freq = params->frequency; + + if (fe->ops.info.type == FE_ATSC) { + switch (params->u.vsb.modulation) { + case VSB_8: + case VSB_16: + mode = MxL_MODE_OTA_DVBT_ATSC; + break; + case QAM_64: + case QAM_256: + mode = MxL_MODE_CABLE_DIGITAL; + break; + default: + mxl_err("modulation not set!"); + return -EINVAL; + } + bw = MxL_BW_6MHz; + } else if (fe->ops.info.type == FE_OFDM) { + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + bw = MxL_BW_6MHz; + break; + case BANDWIDTH_7_MHZ: + bw = MxL_BW_7MHz; + break; + case BANDWIDTH_8_MHZ: + bw = MxL_BW_8MHz; + break; + default: + mxl_err("bandwidth not set!"); + return -EINVAL; + } + mode = MxL_MODE_OTA_DVBT_ATSC; + } else { + mxl_err("modulation type not supported!"); + return -EINVAL; + } + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + mutex_lock(&state->lock); + + ret = mxl5007t_tuner_init(state, mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_tuner_rf_tune(state, freq, bw); + if (mxl_fail(ret)) + goto fail; + + state->frequency = freq; + state->bandwidth = (fe->ops.info.type == FE_OFDM) ? + params->u.ofdm.bandwidth : 0; +fail: + mutex_unlock(&state->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +static int mxl5007t_set_analog_params(struct dvb_frontend *fe, + struct analog_parameters *params) +{ + struct mxl5007t_state *state = fe->tuner_priv; + enum mxl5007t_bw_mhz bw = 0; /* FIXME */ + enum mxl5007t_mode cbl_mode; + enum mxl5007t_mode ota_mode; + char *mode_name; + int ret; + u32 freq = params->frequency * 62500; + +#if 0 + if (params->mode == V4L2_TUNER_RADIO) { + freq = freq / 1000; + mode_name = "fm"; + } else +#else +#define cable 1 +#endif + if (params->std & V4L2_STD_MN) { + cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH; + ota_mode = MxL_MODE_OTA_NTSC_PAL_GH; + mode_name = "MN"; + } else if (params->std & V4L2_STD_B) { + cbl_mode = MxL_MODE_CABLE_PAL_IB; + ota_mode = MxL_MODE_OTA_PAL_IB; + mode_name = "B"; + } else if (params->std & V4L2_STD_GH) { + cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH; + ota_mode = MxL_MODE_OTA_NTSC_PAL_GH; + mode_name = "GH"; + } else if (params->std & V4L2_STD_PAL_I) { + cbl_mode = MxL_MODE_CABLE_PAL_IB; + ota_mode = MxL_MODE_OTA_PAL_IB; + mode_name = "I"; + } else if (params->std & V4L2_STD_DK) { + cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL; + ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL; + mode_name = "DK"; + } else if (params->std & V4L2_STD_SECAM_L) { + cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL; + ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL; + mode_name = "L"; + } else if (params->std & V4L2_STD_SECAM_LC) { + cbl_mode = MxL_MODE_CABLE_PAL_D_SECAM_KL; + ota_mode = MxL_MODE_OTA_PAL_D_SECAM_KL; + mode_name = "L'"; + } else { + mode_name = "xx"; + /* FIXME */ + cbl_mode = MxL_MODE_CABLE_NTSC_PAL_GH; + ota_mode = MxL_MODE_OTA_NTSC_PAL_GH; + } + mxl_debug("setting mxl5007 to system %s", mode_name); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + mutex_lock(&state->lock); + + ret = mxl5007t_tuner_init(state, cable ? cbl_mode : ota_mode); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_tuner_rf_tune(state, freq, bw); + if (mxl_fail(ret)) + goto fail; + + state->frequency = freq; + state->bandwidth = 0; +fail: + mutex_unlock(&state->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_init(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + int ret; + u8 d; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_read_reg(state, 0x05, &d); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_write_reg(state, 0x05, d | 0x01); + mxl_fail(ret); +fail: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +static int mxl5007t_sleep(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + int ret; + u8 d; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_read_reg(state, 0x05, &d); + if (mxl_fail(ret)) + goto fail; + + ret = mxl5007t_write_reg(state, 0x05, d & ~0x01); + mxl_fail(ret); +fail: + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + return ret; +} + +/* ------------------------------------------------------------------------- */ + +static int mxl5007t_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct mxl5007t_state *state = fe->tuner_priv; + *frequency = state->frequency; + return 0; +} + +static int mxl5007t_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct mxl5007t_state *state = fe->tuner_priv; + *bandwidth = state->bandwidth; + return 0; +} + +static int mxl5007t_release(struct dvb_frontend *fe) +{ + struct mxl5007t_state *state = fe->tuner_priv; + + mutex_lock(&mxl5007t_list_mutex); + + if (state) + hybrid_tuner_release_state(state); + + mutex_unlock(&mxl5007t_list_mutex); + + fe->tuner_priv = NULL; + + return 0; +} + +/* ------------------------------------------------------------------------- */ + +static struct dvb_tuner_ops mxl5007t_tuner_ops = { + .info = { + .name = "MaxLinear MxL5007T", +#if 0 + .frequency_min = , + .frequency_max = , + .frequency_step = , +#endif + }, + .init = mxl5007t_init, + .sleep = mxl5007t_sleep, + .set_params = mxl5007t_set_params, + .set_analog_params = mxl5007t_set_analog_params, + .get_status = mxl5007t_get_status, + .get_frequency = mxl5007t_get_frequency, + .get_bandwidth = mxl5007t_get_bandwidth, + .release = mxl5007t_release, +}; + +static int mxl5007t_get_chip_id(struct mxl5007t_state *state) +{ + char *name; + int ret; + u8 id; + + ret = mxl5007t_read_reg(state, 0xd3, &id); + if (mxl_fail(ret)) + goto fail; + + switch (id) { + case MxL_5007_V1_F1: + name = "MxL5007.v1.f1"; + break; + case MxL_5007_V1_F2: + name = "MxL5007.v1.f2"; + break; + case MxL_5007_V2_100_F1: + name = "MxL5007.v2.100.f1"; + break; + case MxL_5007_V2_100_F2: + name = "MxL5007.v2.100.f2"; + break; + case MxL_5007_V2_200_F1: + name = "MxL5007.v2.200.f1"; + break; + case MxL_5007_V2_200_F2: + name = "MxL5007.v2.200.f2"; + break; + default: +#if 0 + ret = -EINVAL; + goto fail; +#else + name = "MxL5007T"; + id = MxL_UNKNOWN_ID; +#endif + } + state->chip_id = id; + mxl_info("%s detected @ %d-%04x", name, + i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr); + return 0; +fail: + mxl_warn("unable to identify device @ %d-%04x", + i2c_adapter_id(state->i2c_props.adap), + state->i2c_props.addr); + + state->chip_id = MxL_UNKNOWN_ID; + return ret; +} + +struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 addr, + struct mxl5007t_config *cfg) +{ + struct mxl5007t_state *state = NULL; + int instance, ret; + + mutex_lock(&mxl5007t_list_mutex); + instance = hybrid_tuner_request_state(struct mxl5007t_state, state, + hybrid_tuner_instance_list, + i2c, addr, "mxl5007"); + switch (instance) { + case 0: + goto fail; + break; + case 1: + /* new tuner instance */ + state->config = cfg; + + mutex_init(&state->lock); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + + ret = mxl5007t_get_chip_id(state); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + + /* check return value of mxl5007t_get_chip_id */ + if (mxl_fail(ret)) + goto fail; + break; + default: + /* existing tuner instance */ + break; + } + fe->tuner_priv = state; + mutex_unlock(&mxl5007t_list_mutex); + + memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops, + sizeof(struct dvb_tuner_ops)); + + return fe; +fail: + mutex_unlock(&mxl5007t_list_mutex); + + mxl5007t_release(fe); + return NULL; +} +EXPORT_SYMBOL_GPL(mxl5007t_attach); +MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver"); +MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.1"); + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ diff --git a/linux/drivers/media/common/tuners/mxl5007t.h b/linux/drivers/media/common/tuners/mxl5007t.h new file mode 100644 index 000000000..aa3eea0b5 --- /dev/null +++ b/linux/drivers/media/common/tuners/mxl5007t.h @@ -0,0 +1,104 @@ +/* + * mxl5007t.h - driver for the MaxLinear MxL5007T silicon tuner + * + * Copyright (C) 2008 Michael Krufky <mkrufky@linuxtv.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef __MXL5007T_H__ +#define __MXL5007T_H__ + +#include "dvb_frontend.h" + +/* ------------------------------------------------------------------------- */ + +enum mxl5007t_if_freq { + MxL_IF_4_MHZ, /* 4000000 */ + MxL_IF_4_5_MHZ, /* 4500000 */ + MxL_IF_4_57_MHZ, /* 4570000 */ + MxL_IF_5_MHZ, /* 5000000 */ + MxL_IF_5_38_MHZ, /* 5380000 */ + MxL_IF_6_MHZ, /* 6000000 */ + MxL_IF_6_28_MHZ, /* 6280000 */ + MxL_IF_9_1915_MHZ, /* 9191500 */ + MxL_IF_35_25_MHZ, /* 35250000 */ + MxL_IF_36_15_MHZ, /* 36150000 */ + MxL_IF_44_MHZ, /* 44000000 */ +}; + +enum mxl5007t_xtal_freq { + MxL_XTAL_16_MHZ, /* 16000000 */ + MxL_XTAL_20_MHZ, /* 20000000 */ + MxL_XTAL_20_25_MHZ, /* 20250000 */ + MxL_XTAL_20_48_MHZ, /* 20480000 */ + MxL_XTAL_24_MHZ, /* 24000000 */ + MxL_XTAL_25_MHZ, /* 25000000 */ + MxL_XTAL_25_14_MHZ, /* 25140000 */ + MxL_XTAL_27_MHZ, /* 27000000 */ + MxL_XTAL_28_8_MHZ, /* 28800000 */ + MxL_XTAL_32_MHZ, /* 32000000 */ + MxL_XTAL_40_MHZ, /* 40000000 */ + MxL_XTAL_44_MHZ, /* 44000000 */ + MxL_XTAL_48_MHZ, /* 48000000 */ + MxL_XTAL_49_3811_MHZ, /* 49381100 */ +}; + +enum mxl5007t_clkout_amp { + MxL_CLKOUT_AMP_0_94V = 0, + MxL_CLKOUT_AMP_0_53V = 1, + MxL_CLKOUT_AMP_0_37V = 2, + MxL_CLKOUT_AMP_0_28V = 3, + MxL_CLKOUT_AMP_0_23V = 4, + MxL_CLKOUT_AMP_0_20V = 5, + MxL_CLKOUT_AMP_0_17V = 6, + MxL_CLKOUT_AMP_0_15V = 7, +}; + +struct mxl5007t_config { + s32 if_diff_out_level; + enum mxl5007t_clkout_amp clk_out_amp; + enum mxl5007t_xtal_freq xtal_freq_hz; + enum mxl5007t_if_freq if_freq_hz; + unsigned int invert_if:1; + unsigned int loop_thru_enable:1; + unsigned int clk_out_enable:1; +}; + +#if defined(CONFIG_MEDIA_TUNER_MXL5007T) || (defined(CONFIG_MEDIA_TUNER_MXL5007T_MODULE) && defined(MODULE)) +extern struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 addr, + struct mxl5007t_config *cfg); +#else +static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, + u8 addr, + struct mxl5007t_config *cfg) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif + +#endif /* __MXL5007T_H__ */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * --------------------------------------------------------------------------- + * Local variables: + * c-basic-offset: 8 + * End: + */ + diff --git a/linux/drivers/media/common/tuners/tda9887.c b/linux/drivers/media/common/tuners/tda9887.c index 61a56026d..d588c5d88 100644 --- a/linux/drivers/media/common/tuners/tda9887.c +++ b/linux/drivers/media/common/tuners/tda9887.c @@ -6,12 +6,12 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/delay.h> -#include "compat.h" -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/tuner.h> #include "tuner-i2c.h" #include "tda9887.h" +#include "compat.h" /* Chips: diff --git a/linux/drivers/media/common/tuners/tuner-simple.c b/linux/drivers/media/common/tuners/tuner-simple.c index a029cf8f5..a709d6bee 100644 --- a/linux/drivers/media/common/tuners/tuner-simple.c +++ b/linux/drivers/media/common/tuners/tuner-simple.c @@ -7,7 +7,7 @@ #include <linux/delay.h> #include <linux/i2c.h> #include "compat.h" -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <media/tuner.h> #include <media/v4l2-common.h> #include <media/tuner-types.h> @@ -143,6 +143,7 @@ static inline int tuner_stereo(const int type, const int status) case TUNER_PHILIPS_FM1236_MK3: case TUNER_PHILIPS_FM1256_IH3: case TUNER_LG_NTSC_TAPE: + case TUNER_TCL_MF02GIP_5N: return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3); default: return status & TUNER_STEREO; @@ -514,6 +515,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) case TUNER_PHILIPS_FMD1216ME_MK3: case TUNER_LG_NTSC_TAPE: case TUNER_PHILIPS_FM1256_IH3: + case TUNER_TCL_MF02GIP_5N: buffer[3] = 0x19; break; case TUNER_TNF_5335MF: diff --git a/linux/drivers/media/common/tuners/tuner-types.c b/linux/drivers/media/common/tuners/tuner-types.c index b3f0f62e0..861d23872 100644 --- a/linux/drivers/media/common/tuners/tuner-types.c +++ b/linux/drivers/media/common/tuners/tuner-types.c @@ -1217,6 +1217,23 @@ static struct tuner_params tuner_samsung_tcpg_6121p30a_params[] = { }, }; +/* ------------ TUNER_TCL_MF02GIP-5N-E - TCL MF02GIP-5N ------------ */ + +static struct tuner_range tuner_tcl_mf02gip_5n_ntsc_ranges[] = { + { 16 * 172.00 /*MHz*/, 0x8e, 0x01, }, + { 16 * 448.00 /*MHz*/, 0x8e, 0x02, }, + { 16 * 999.99 , 0x8e, 0x04, }, +}; + +static struct tuner_params tuner_tcl_mf02gip_5n_params[] = { + { + .type = TUNER_PARAM_TYPE_NTSC, + .ranges = tuner_tcl_mf02gip_5n_ntsc_ranges, + .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_ntsc_ranges), + .cb_first_if_lower_freq = 1, + }, +}; + /* --------------------------------------------------------------------- */ struct tunertype tuners[] = { @@ -1642,6 +1659,11 @@ struct tunertype tuners[] = { .name = "Xceive 5000 tuner", /* see xc5000.c for details */ }, + [TUNER_TCL_MF02GIP_5N] = { /* TCL tuner MF02GIP-5N-E */ + .name = "TCL tuner MF02GIP-5N-E", + .params = tuner_tcl_mf02gip_5n_params, + .count = ARRAY_SIZE(tuner_tcl_mf02gip_5n_params), + }, }; EXPORT_SYMBOL(tuners); diff --git a/linux/drivers/media/dvb/bt8xx/Kconfig b/linux/drivers/media/dvb/bt8xx/Kconfig index 7588db131..7e9c090fc 100644 --- a/linux/drivers/media/dvb/bt8xx/Kconfig +++ b/linux/drivers/media/dvb/bt8xx/Kconfig @@ -1,7 +1,6 @@ config DVB_BT8XX tristate "BT8xx based PCI cards" depends on DVB_CORE && PCI && I2C && VIDEO_BT848 - depends on HOTPLUG # due to FW_LOADER select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_SP887X if !DVB_FE_CUSTOMISE select DVB_NXT6000 if !DVB_FE_CUSTOMISE @@ -10,7 +9,6 @@ config DVB_BT8XX select DVB_LGDT330X if !DVB_FE_CUSTOMISE select DVB_ZL10353 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE - select FW_LOADER help Support for PCI cards based on the Bt8xx PCI bridge. Examples are the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig index 3c663c65e..8a54cb483 100644 --- a/linux/drivers/media/dvb/dvb-usb/Kconfig +++ b/linux/drivers/media/dvb/dvb-usb/Kconfig @@ -1,8 +1,6 @@ config DVB_USB tristate "Support for various USB DVB devices" depends on DVB_CORE && USB && I2C && INPUT - depends on HOTPLUG # due to FW_LOADER - select FW_LOADER help By enabling this you will be able to choose the various supported USB1.1 and USB2.0 DVB devices. @@ -110,6 +108,8 @@ config DVB_USB_CXUSB select MEDIA_TUNER_SIMPLE if !DVB_FE_CUSTOMISE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_MXL5005S if !DVB_FE_CUSTOMISE + select DVB_DIB7000P if !DVB_FE_CUSTOMISE + select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode diff --git a/linux/drivers/media/dvb/dvb-usb/anysee.c b/linux/drivers/media/dvb/dvb-usb/anysee.c index adfd4fc82..2f408d2e1 100644 --- a/linux/drivers/media/dvb/dvb-usb/anysee.c +++ b/linux/drivers/media/dvb/dvb-usb/anysee.c @@ -43,7 +43,7 @@ module_param_named(debug, dvb_usb_anysee_debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level" DVB_USB_DEBUG_STATUS); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -struct mutex anysee_usb_mutex; +static struct mutex anysee_usb_mutex; static int anysee_ctrl_msg(struct dvb_usb_device *d, u8 *sbuf, u8 slen, u8 *rbuf, u8 rlen) diff --git a/linux/drivers/media/dvb/dvb-usb/cxusb.c b/linux/drivers/media/dvb/dvb-usb/cxusb.c index 578afce68..49985f992 100644 --- a/linux/drivers/media/dvb/dvb-usb/cxusb.c +++ b/linux/drivers/media/dvb/dvb-usb/cxusb.c @@ -36,6 +36,9 @@ #include "tuner-xc2028.h" #include "tuner-simple.h" #include "mxl5005s.h" +#include "dib7000p.h" +#include "dib0070.h" +#include "lgs8gl5.h" /* debug */ static int dvb_usb_cxusb_debug; @@ -109,6 +112,25 @@ static void cxusb_nano2_led(struct dvb_usb_device *d, int onoff) cxusb_bluebird_gpio_rw(d, 0x40, onoff ? 0 : 0x40); } +static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, + u8 addr, int onoff) +{ + u8 o[2] = {addr, onoff}; + u8 i; + int rc; + + rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + + if (rc < 0) + return rc; + if (i == 0x01) + return 0; + else { + deb_info("gpio_write failed.\n"); + return -EIO; + } +} + /* I2C */ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) @@ -262,6 +284,20 @@ static int cxusb_nano2_power_ctrl(struct dvb_usb_device *d, int onoff) return rc; } +static int cxusb_d680_dmb_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + int ret; + u8 b; + ret = cxusb_power_ctrl(d, onoff); + if (!onoff) + return ret; + + msleep(128); + cxusb_ctrl_msg(d, CMD_DIGITAL, NULL, 0, &b, 1); + msleep(100); + return ret; +} + static int cxusb_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) { u8 buf[2] = { 0x03, 0x00 }; @@ -283,6 +319,67 @@ static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return 0; } +static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) +{ + int ep = d->props.generic_bulk_ctrl_endpoint; + const int timeout = 100; + const int junk_len = 32; + u8 *junk; + int rd_count; + + /* Discard remaining data in video pipe */ + junk = kmalloc(junk_len, GFP_KERNEL); + if (!junk) + return; + while (1) { + if (usb_bulk_msg(d->udev, + usb_rcvbulkpipe(d->udev, ep), + junk, junk_len, &rd_count, timeout) < 0) + break; + if (!rd_count) + break; + } + kfree(junk); +} + +static void cxusb_d680_dmb_drain_video(struct dvb_usb_device *d) +{ + struct usb_data_stream_properties *p = &d->props.adapter[0].stream; + const int timeout = 100; + const int junk_len = p->u.bulk.buffersize; + u8 *junk; + int rd_count; + + /* Discard remaining data in video pipe */ + junk = kmalloc(junk_len, GFP_KERNEL); + if (!junk) + return; + while (1) { + if (usb_bulk_msg(d->udev, + usb_rcvbulkpipe(d->udev, p->endpoint), + junk, junk_len, &rd_count, timeout) < 0) + break; + if (!rd_count) + break; + } + kfree(junk); +} + +static int cxusb_d680_dmb_streaming_ctrl( + struct dvb_usb_adapter *adap, int onoff) +{ + if (onoff) { + u8 buf[2] = { 0x03, 0x00 }; + cxusb_d680_dmb_drain_video(adap->dev); + return cxusb_ctrl_msg(adap->dev, CMD_STREAMING_ON, + buf, sizeof(buf), NULL, 0); + } else { + int ret = cxusb_ctrl_msg(adap->dev, + CMD_STREAMING_OFF, NULL, 0, NULL, 0); + return ret; + } +} + static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) { struct dvb_usb_rc_key *keymap = d->props.rc_key_map; @@ -335,6 +432,32 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event, return 0; } +static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event, + int *state) +{ + struct dvb_usb_rc_key *keymap = d->props.rc_key_map; + u8 ircode[2]; + int i; + + *event = 0; + *state = REMOTE_NO_KEY_PRESSED; + + if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0) + return 0; + + for (i = 0; i < d->props.rc_key_map_size; i++) { + if (keymap[i].custom == ircode[0] && + keymap[i].data == ircode[1]) { + *event = keymap[i].event; + *state = REMOTE_KEY_PRESSED; + + return 0; + } + } + + return 0; +} + static struct dvb_usb_rc_key dvico_mce_rc_keys[] = { { 0xfe, 0x02, KEY_TV }, { 0xfe, 0x0e, KEY_MP3 }, @@ -422,6 +545,44 @@ static struct dvb_usb_rc_key dvico_portable_rc_keys[] = { { 0xfc, 0x00, KEY_UNKNOWN }, /* HD */ }; +static struct dvb_usb_rc_key d680_dmb_rc_keys[] = { + { 0x00, 0x38, KEY_UNKNOWN }, /* TV/AV */ + { 0x08, 0x0c, KEY_ZOOM }, + { 0x08, 0x00, KEY_0 }, + { 0x00, 0x01, KEY_1 }, + { 0x08, 0x02, KEY_2 }, + { 0x00, 0x03, KEY_3 }, + { 0x08, 0x04, KEY_4 }, + { 0x00, 0x05, KEY_5 }, + { 0x08, 0x06, KEY_6 }, + { 0x00, 0x07, KEY_7 }, + { 0x08, 0x08, KEY_8 }, + { 0x00, 0x09, KEY_9 }, + { 0x00, 0x0a, KEY_MUTE }, + { 0x08, 0x29, KEY_BACK }, + { 0x00, 0x12, KEY_CHANNELUP }, + { 0x08, 0x13, KEY_CHANNELDOWN }, + { 0x00, 0x2b, KEY_VOLUMEUP }, + { 0x08, 0x2c, KEY_VOLUMEDOWN }, + { 0x00, 0x20, KEY_UP }, + { 0x08, 0x21, KEY_DOWN }, + { 0x00, 0x11, KEY_LEFT }, + { 0x08, 0x10, KEY_RIGHT }, + { 0x00, 0x0d, KEY_OK }, + { 0x08, 0x1f, KEY_RECORD }, + { 0x00, 0x17, KEY_PLAYPAUSE }, + { 0x08, 0x16, KEY_PLAYPAUSE }, + { 0x00, 0x0b, KEY_STOP }, + { 0x08, 0x27, KEY_FASTFORWARD }, + { 0x00, 0x26, KEY_REWIND }, + { 0x08, 0x1e, KEY_UNKNOWN }, /* Time Shift */ + { 0x00, 0x0e, KEY_UNKNOWN }, /* Snapshot */ + { 0x08, 0x2d, KEY_UNKNOWN }, /* Mouse Cursor */ + { 0x00, 0x0f, KEY_UNKNOWN }, /* Minimize/Maximize */ + { 0x08, 0x14, KEY_UNKNOWN }, /* Shuffle */ + { 0x00, 0x25, KEY_POWER }, +}; + static int cxusb_dee1601_demod_init(struct dvb_frontend* fe) { static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 }; @@ -527,6 +688,24 @@ static struct mxl5005s_config aver_a868r_tuner = { .AgcMasterByte = 0x00, }; +/* FIXME: needs tweaking */ +static struct mxl5005s_config d680_dmb_tuner = { + .i2c_address = 0x63, + .if_freq = 36125000UL, + .xtal_freq = CRYSTAL_FREQ_16000000HZ, + .agc_mode = MXL_SINGLE_AGC, + .tracking_filter = MXL_TF_C, + .rssi_enable = MXL_RSSI_ENABLE, + .cap_select = MXL_CAP_SEL_ENABLE, + .div_out = MXL_DIV_OUT_4, + .clock_out = MXL_CLOCK_OUT_DISABLE, + .output_load = MXL5005S_IF_OUTPUT_LOAD_200_OHM, + .top = MXL5005S_TOP_25P2, + .mod_mode = MXL_DIGITAL_MODE, + .if_mode = MXL_ZERO_IF, + .AgcMasterByte = 0x00, +}; + /* Callbacks for DVB USB */ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap) { @@ -565,7 +744,8 @@ static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap) static int dvico_bluebird_xc2028_callback(void *ptr, int command, int arg) { - struct dvb_usb_device *d = ptr; + struct dvb_usb_adapter *adap = ptr; + struct dvb_usb_device *d = adap->dev; switch (command) { case XC2028_TUNER_RESET: @@ -593,9 +773,9 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap) .callback = dvico_bluebird_xc2028_callback, }; static struct xc2028_ctrl ctl = { - .fname = "xc3028-dvico-au-01.fw", + .fname = "xc3028-v27.fw", .max_len = 64, - .scode_table = XC3028_FE_ZARLINK456, + .demod = XC3028_FE_ZARLINK456, }; fe = dvb_attach(xc2028_attach, adap->fe, &cfg); @@ -614,6 +794,14 @@ static int cxusb_mxl5003s_tuner_attach(struct dvb_usb_adapter *adap) return 0; } +static int cxusb_d680_dmb_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_frontend *fe; + fe = dvb_attach(mxl5005s_attach, adap->fe, + &adap->dev->i2c_adap, &d680_dmb_tuner); + return (fe == NULL) ? -EIO : 0; +} + static int cxusb_cx22702_frontend_attach(struct dvb_usb_adapter *adap) { u8 b; @@ -725,6 +913,159 @@ no_IR: return 0; } +static struct dibx000_agc_config dib7070_agc_config = { + .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + + /* + * P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=5, + * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, + * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 + */ + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | + (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), + .inv_gain = 600, + .time_stabiliz = 10, + .alpha_level = 0, + .thlock = 118, + .wbd_inv = 0, + .wbd_ref = 3530, + .wbd_sel = 1, + .wbd_alpha = 5, + .agc1_max = 65535, + .agc1_min = 0, + .agc2_max = 65535, + .agc2_min = 0, + .agc1_pt1 = 0, + .agc1_pt2 = 40, + .agc1_pt3 = 183, + .agc1_slope1 = 206, + .agc1_slope2 = 255, + .agc2_pt1 = 72, + .agc2_pt2 = 152, + .agc2_slope1 = 88, + .agc2_slope2 = 90, + .alpha_mant = 17, + .alpha_exp = 27, + .beta_mant = 23, + .beta_exp = 51, + .perform_agc_softsplit = 0, +}; + +static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { + .internal = 60000, + .sampling = 15000, + .pll_prediv = 1, + .pll_ratio = 20, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 2, + /* refsel, sel, freq_15k */ + .sad_cfg = (3 << 14) | (1 << 12) | (524 << 0), + .ifreq = (0 << 25) | 0, + .timf = 20452225, + .xtal_hz = 12000000, +}; + +static struct dib7000p_config cxusb_dualdig4_rev2_config = { + .output_mode = OUTMODE_MPEG2_PAR_GATED_CLK, + .output_mpeg2_in_188_bytes = 1, + + .agc_config_count = 1, + .agc = &dib7070_agc_config, + .bw = &dib7070_bw_config_12_mhz, + .tuner_is_baseband = 1, + .spur_protect = 1, + + .gpio_dir = 0xfcef, + .gpio_val = 0x0110, + + .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS, + + .hostbus_diversity = 1, +}; + +static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) +{ + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) + err("set interface failed"); + + cxusb_ctrl_msg(adap->dev, CMD_DIGITAL, NULL, 0, NULL, 0); + + cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); + + dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &cxusb_dualdig4_rev2_config); + + adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + &cxusb_dualdig4_rev2_config); + if (adap->fe == NULL) + return -EIO; + + return 0; +} + +static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) +{ + return dib7000p_set_gpio(fe, 8, 0, !onoff); +} + +static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) +{ + return 0; +} + +static struct dib0070_config dib7070p_dib0070_config = { + .i2c_address = DEFAULT_DIB0070_I2C_ADDRESS, + .reset = dib7070_tuner_reset, + .sleep = dib7070_tuner_sleep, + .clock_khz = 12000, +}; + +struct dib0700_adapter_state { + int (*set_param_save) (struct dvb_frontend *, + struct dvb_frontend_parameters *); +}; + +static int dib7070_set_param_override(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + u16 offset; + u8 band = BAND_OF_FREQUENCY(fep->frequency/1000); + switch (band) { + case BAND_VHF: offset = 950; break; + default: + case BAND_UHF: offset = 550; break; + } + + dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + + return state->set_param_save(fe, fep); +} + +static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) +{ + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = + dib7000p_get_i2c_master(adap->fe, + DIBX000_I2C_INTERFACE_TUNER, 1); + + if (dvb_attach(dib0070_attach, adap->fe, tun_i2c, + &dib7070p_dib0070_config) == NULL) + return -ENODEV; + + st->set_param_save = adap->fe->ops.tuner_ops.set_params; + adap->fe->ops.tuner_ops.set_params = dib7070_set_param_override; + return 0; +} + static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) { if (usb_set_interface(adap->dev->udev, 0, 1) < 0) @@ -750,6 +1091,54 @@ static int cxusb_nano2_frontend_attach(struct dvb_usb_adapter *adap) return -EIO; } +static struct lgs8gl5_config lgs8gl5_cfg = { + .demod_address = 0x19, +}; + +static int cxusb_d680_dmb_frontend_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + int n; + + /* Select required USB configuration */ + if (usb_set_interface(d->udev, 0, 0) < 0) + err("set interface failed"); + + /* Unblock all USB pipes */ + usb_clear_halt(d->udev, + usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint)); + usb_clear_halt(d->udev, + usb_rcvbulkpipe(d->udev, d->props.adapter[0].stream.endpoint)); + + /* Drain USB pipes to avoid hang after reboot */ + for (n = 0; n < 5; n++) { + cxusb_d680_dmb_drain_message(d); + cxusb_d680_dmb_drain_video(d); + msleep(200); + } + + /* Reset the tuner */ + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 0) < 0) { + err("clear tuner gpio failed"); + return -EIO; + } + msleep(100); + if (cxusb_d680_dmb_gpio_tuner(d, 0x07, 1) < 0) { + err("set tuner gpio failed"); + return -EIO; + } + msleep(100); + + /* Attach frontend */ + adap->fe = dvb_attach(lgs8gl5_attach, &lgs8gl5_cfg, &d->i2c_adap); + if (adap->fe == NULL) + return -EIO; + + return 0; +} + /* * DViCO has shipped two devices with the same USB ID, but only one of them * needs a firmware download. Check the device class details to see if they @@ -825,9 +1214,11 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties; static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties; static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties; static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties; +static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties; static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_properties; static struct dvb_usb_device_properties cxusb_aver_a868r_properties; +static struct dvb_usb_device_properties cxusb_d680_dmb_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -851,6 +1242,11 @@ static int cxusb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &cxusb_aver_a868r_properties, THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, + &cxusb_bluebird_dualdig4_rev2_properties, + THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_d680_dmb_properties, + THIS_MODULE, NULL, adapter_nr) || 0) return 0; @@ -875,6 +1271,8 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM) }, { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_A868R) }, + { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, + { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -1320,6 +1718,104 @@ static struct dvb_usb_device_properties cxusb_aver_a868r_properties = { } }; +static +struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_streaming_ctrl, + .frontend_attach = cxusb_dualdig4_rev2_frontend_attach, + .tuner_attach = cxusb_dualdig4_rev2_tuner_attach, + .size_of_priv = sizeof(struct dib0700_adapter_state), + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 7, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + }, + }, + + .power_ctrl = cxusb_bluebird_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = dvico_mce_rc_keys, + .rc_key_map_size = ARRAY_SIZE(dvico_mce_rc_keys), + .rc_query = cxusb_rc_query, + + .num_device_descs = 1, + .devices = { + { "DViCO FusionHDTV DVB-T Dual Digital 4 (rev 2)", + { NULL }, + { &cxusb_table[17], NULL }, + }, + } +}; + +static struct dvb_usb_device_properties cxusb_d680_dmb_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .streaming_ctrl = cxusb_d680_dmb_streaming_ctrl, + .frontend_attach = cxusb_d680_dmb_frontend_attach, + .tuner_attach = cxusb_d680_dmb_tuner_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 5, + .endpoint = 0x02, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + }, + }, + + .power_ctrl = cxusb_d680_dmb_power_ctrl, + + .i2c_algo = &cxusb_i2c_algo, + + .generic_bulk_ctrl_endpoint = 0x01, + + .rc_interval = 100, + .rc_key_map = d680_dmb_rc_keys, + .rc_key_map_size = ARRAY_SIZE(d680_dmb_rc_keys), + .rc_query = cxusb_d680_dmb_rc_query, + + .num_device_descs = 1, + .devices = { + { + "Conexant DMB-TH Stick", + { NULL }, + { &cxusb_table[18], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index 029b437ca..851070b86 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -22,6 +22,7 @@ #define USB_VID_AVERMEDIA 0x07ca #define USB_VID_COMPRO 0x185b #define USB_VID_COMPRO_UNK 0x145f +#define USB_VID_CONEXANT 0x0572 #define USB_VID_CYPRESS 0x04b4 #define USB_VID_DIBCOM 0x10b8 #define USB_VID_DPOSH 0x1498 @@ -69,6 +70,7 @@ #define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d #define USB_PID_COMPRO_VIDEOMATE_U500 0x1e78 #define USB_PID_COMPRO_VIDEOMATE_U500_PC 0x1e80 +#define USB_PID_CONEXANT_D680_DMB 0x86d6 #define USB_PID_DIBCOM_HOOK_DEFAULT 0x0064 #define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM 0x0065 #define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8 @@ -170,6 +172,7 @@ #define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD 0xdb58 #define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM 0xdb59 #define USB_PID_DVICO_BLUEBIRD_DUAL_4 0xdb78 +#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2 0xdb98 #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2 0xdb70 #define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM 0xdb71 #define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD 0xdb54 diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig index fa7f0c563..774f5c2a7 100644 --- a/linux/drivers/media/dvb/frontends/Kconfig +++ b/linux/drivers/media/dvb/frontends/Kconfig @@ -97,9 +97,8 @@ comment "DVB-T (terrestrial) frontends" config DVB_SP8870 tristate "Spase sp8870 based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -110,9 +109,8 @@ config DVB_SP8870 config DVB_SP887X tristate "Spase sp887x based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -137,9 +135,8 @@ config DVB_CX22702 config DVB_DRX397XD tristate "Micronas DRX3975D/DRX3977D based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -158,9 +155,8 @@ config DVB_L64781 config DVB_TDA1004X tristate "Philips TDA10045H/TDA10046H based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -225,9 +221,8 @@ config DVB_DIB7000P config DVB_TDA10048 tristate "Philips TDA10048HN based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help A DVB-T tuner module. Say Y when you want to support this frontend. @@ -267,9 +262,8 @@ comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends" config DVB_NXT200X tristate "NxtWave Communications NXT2002/NXT2004 based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -282,9 +276,8 @@ config DVB_NXT200X config DVB_OR51211 tristate "Oren OR51211 based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help An ATSC 8VSB tuner module. Say Y when you want to support this frontend. @@ -295,9 +288,8 @@ config DVB_OR51211 config DVB_OR51132 tristate "Oren OR51132 based" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -311,9 +303,8 @@ config DVB_OR51132 config DVB_BCM3510 tristate "Broadcom BCM3510" - depends on DVB_CORE && I2C && HOTPLUG + depends on DVB_CORE && I2C default m if DVB_FE_CUSTOMISE - select FW_LOADER help An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. @@ -394,4 +385,11 @@ config DVB_ISL6421 help An SEC control chip. +config DVB_LGS8GL5 + tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" + depends on DVB_CORE && I2C + default m if DVB_FE_CUSTOMISE + help + A DMB-TH tuner module. Say Y when you want to support this frontend. + endmenu diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile index 028da5561..262eaa429 100644 --- a/linux/drivers/media/dvb/frontends/Makefile +++ b/linux/drivers/media/dvb/frontends/Makefile @@ -48,3 +48,4 @@ obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o obj-$(CONFIG_DVB_AU8522) += au8522.o obj-$(CONFIG_DVB_TDA10048) += tda10048.o obj-$(CONFIG_DVB_S5H1411) += s5h1411.o +obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o diff --git a/linux/drivers/media/dvb/frontends/au8522.c b/linux/drivers/media/dvb/frontends/au8522.c index 37f6260e1..d946c8beb 100644 --- a/linux/drivers/media/dvb/frontends/au8522.c +++ b/linux/drivers/media/dvb/frontends/au8522.c @@ -304,6 +304,43 @@ static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse, return ret; } +static int au8522_set_if(struct dvb_frontend *fe, enum au8522_if_freq if_freq) +{ + struct au8522_state *state = fe->demodulator_priv; + u8 r0b5, r0b6, r0b7; + char *ifmhz; + + switch (if_freq) { + case AU8522_IF_3_25MHZ: + ifmhz = "3.25"; + r0b5 = 0x00; + r0b6 = 0x3d; + r0b7 = 0xa0; + break; + case AU8522_IF_4MHZ: + ifmhz = "4.00"; + r0b5 = 0x00; + r0b6 = 0x4b; + r0b7 = 0xd9; + break; + case AU8522_IF_6MHZ: + ifmhz = "6.00"; + r0b5 = 0xfb; + r0b6 = 0x8e; + r0b7 = 0x39; + break; + default: + dprintk("%s() IF Frequency not supported\n", __func__); + return -EINVAL; + } + dprintk("%s() %s MHz\n", __func__, ifmhz); + au8522_writereg(state, 0x80b5, r0b5); + au8522_writereg(state, 0x80b6, r0b6); + au8522_writereg(state, 0x80b7, r0b7); + + return 0; +} + /* VSB Modulation table */ static struct { u16 reg; @@ -334,9 +371,6 @@ static struct { { 0x80af, 0x66 }, { 0x821b, 0xcc }, { 0x821d, 0x80 }, - { 0x80b5, 0xfb }, - { 0x80b6, 0x8e }, - { 0x80b7, 0x39 }, { 0x80a4, 0xe8 }, { 0x8231, 0x13 }, }; @@ -350,9 +384,6 @@ static struct { { 0x80a4, 0x00 }, { 0x8081, 0xc4 }, { 0x80a5, 0x40 }, - { 0x80b5, 0xfb }, - { 0x80b6, 0x8e }, - { 0x80b7, 0x39 }, { 0x80aa, 0x77 }, { 0x80ad, 0x77 }, { 0x80a6, 0x67 }, @@ -438,6 +469,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, au8522_writereg(state, VSB_mod_tab[i].reg, VSB_mod_tab[i].data); + au8522_set_if(fe, state->config->vsb_if); break; case QAM_64: case QAM_256: @@ -446,6 +478,7 @@ static int au8522_enable_modulation(struct dvb_frontend *fe, au8522_writereg(state, QAM_mod_tab[i].reg, QAM_mod_tab[i].data); + au8522_set_if(fe, state->config->qam_if); break; default: dprintk("%s() Invalid modulation\n", __func__); diff --git a/linux/drivers/media/dvb/frontends/au8522.h b/linux/drivers/media/dvb/frontends/au8522.h index d7affa3cd..afc9af26e 100644 --- a/linux/drivers/media/dvb/frontends/au8522.h +++ b/linux/drivers/media/dvb/frontends/au8522.h @@ -24,6 +24,12 @@ #include <linux/dvb/frontend.h> +enum au8522_if_freq { + AU8522_IF_6MHZ = 0, + AU8522_IF_4MHZ, + AU8522_IF_3_25MHZ, +}; + struct au8522_config { /* the demodulator's i2c address */ u8 demod_address; @@ -32,6 +38,9 @@ struct au8522_config { #define AU8522_TUNERLOCKING 0 #define AU8522_DEMODLOCKING 1 u8 status_mode; + + enum au8522_if_freq vsb_if; + enum au8522_if_freq qam_if; }; #if defined(CONFIG_DVB_AU8522) || \ diff --git a/linux/drivers/media/dvb/frontends/dib0070.h b/linux/drivers/media/dvb/frontends/dib0070.h index 3eedfdf50..21f2c5161 100644 --- a/linux/drivers/media/dvb/frontends/dib0070.h +++ b/linux/drivers/media/dvb/frontends/dib0070.h @@ -41,6 +41,7 @@ struct dib0070_config { extern struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dib0070_config *cfg); +extern u16 dib0070_wbd_offset(struct dvb_frontend *); #else static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, @@ -49,9 +50,14 @@ static inline struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } + +static inline u16 dib0070_wbd_offset(struct dvb_frontend *fe) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} #endif extern void dib0070_ctrl_agc_filter(struct dvb_frontend *, uint8_t open); -extern u16 dib0070_wbd_offset(struct dvb_frontend *); #endif diff --git a/linux/drivers/media/dvb/frontends/dib7000p.c b/linux/drivers/media/dvb/frontends/dib7000p.c index c74d373b6..ebb7594e3 100644 --- a/linux/drivers/media/dvb/frontends/dib7000p.c +++ b/linux/drivers/media/dvb/frontends/dib7000p.c @@ -1359,7 +1359,8 @@ struct dvb_frontend * dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, /* Ensure the output mode remains at the previous default if it's * not specifically set by the caller. */ - if (st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) + if ((st->cfg.output_mode != OUTMODE_MPEG2_SERIAL) && + (st->cfg.output_mode != OUTMODE_MPEG2_PAR_GATED_CLK)) st->cfg.output_mode = OUTMODE_MPEG2_FIFO; demod = &st->demod; diff --git a/linux/drivers/media/dvb/frontends/dib7000p.h b/linux/drivers/media/dvb/frontends/dib7000p.h index 07c4d12ed..3e8126857 100644 --- a/linux/drivers/media/dvb/frontends/dib7000p.h +++ b/linux/drivers/media/dvb/frontends/dib7000p.h @@ -41,6 +41,14 @@ struct dib7000p_config { extern struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg); +extern struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *, + enum dibx000_i2c_interface, + int); +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, + int no_of_demods, u8 default_addr, + struct dib7000p_config cfg[]); +extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); +extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); #else static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, @@ -49,13 +57,36 @@ static inline struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif -extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000p_config cfg[]); +static inline +struct i2c_adapter *dib7000p_get_i2c_master(struct dvb_frontend *fe, + enum dibx000_i2c_interface i, int x) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} + +extern int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, + int no_of_demods, u8 default_addr, + struct dib7000p_config cfg[]) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +extern int dib7000p_set_gpio(struct dvb_frontend *fe, u8 num, u8 dir, u8 val) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} + +extern int dib7000p_set_wbd_ref(struct dvb_frontend *fe, u16 value) +{ + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return -ENODEV; +} +#endif -extern struct i2c_adapter * dib7000p_get_i2c_master(struct dvb_frontend *, enum dibx000_i2c_interface, int); extern int dib7000pc_detection(struct i2c_adapter *i2c_adap); -extern int dib7000p_set_gpio(struct dvb_frontend *, u8 num, u8 dir, u8 val); -extern int dib7000p_set_wbd_ref(struct dvb_frontend *, u16 value); #endif diff --git a/linux/drivers/media/dvb/frontends/drx397xD.c b/linux/drivers/media/dvb/frontends/drx397xD.c index 52a9a6553..f1ea891d7 100644 --- a/linux/drivers/media/dvb/frontends/drx397xD.c +++ b/linux/drivers/media/dvb/frontends/drx397xD.c @@ -97,7 +97,7 @@ static void drx_release_fw(struct drx397xD_state *s) { fw_ix_t ix = s->chip_rev; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); write_lock(&fw[ix].lock); if (fw[ix].refcnt) { @@ -114,7 +114,7 @@ static int drx_load_fw(struct drx397xD_state *s, fw_ix_t ix) size_t size, len; int i = 0, j, rc = -EINVAL; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if (ix < 0 || ix >= ARRAY_SIZE(fw)) return -EINVAL; @@ -198,10 +198,10 @@ static int write_fw(struct drx397xD_state *s, blob_ix_t ix) int len, rc = 0, i = 0; if (ix < 0 || ix >= ARRAY_SIZE(blob_name)) { - pr_debug("%s drx_fw_ix_t out of range\n", __FUNCTION__); + pr_debug("%s drx_fw_ix_t out of range\n", __func__); return -EINVAL; } - pr_debug("%s %s\n", __FUNCTION__, blob_name[ix]); + pr_debug("%s %s\n", __func__, blob_name[ix]); read_lock(&fw[s->chip_rev].lock); data = fw[s->chip_rev].data[ix]; @@ -306,7 +306,7 @@ static int PLL_Set(struct drx397xD_state *s, u32 f_tuner, f = fep->frequency; int rc; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if ((f > s->frontend.ops.tuner_ops.info.frequency_max) || (f < s->frontend.ops.tuner_ops.info.frequency_min)) @@ -326,7 +326,7 @@ static int PLL_Set(struct drx397xD_state *s, return rc; *df_tuner = f_tuner - f; - pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __FUNCTION__, f, + pr_debug("%s requested %d [Hz] tuner %d [Hz]\n", __func__, f, f_tuner); return 0; @@ -341,7 +341,7 @@ static int SC_WaitForReady(struct drx397xD_state *s) int cnt = 1000; int rc; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); while (cnt--) { rc = RD16(s, 0x820043); @@ -355,7 +355,7 @@ static int SC_SendCommand(struct drx397xD_state *s, int cmd) { int rc; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); WR16(s, 0x820043, cmd); SC_WaitForReady(s); @@ -369,7 +369,7 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd) { int rc, cnt = 1000; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); rc = WR16(s, 0x420032, cmd); if (rc < 0) @@ -390,7 +390,7 @@ static int HI_Command(struct drx397xD_state *s, u16 cmd) static int HI_CfgCommand(struct drx397xD_state *s) { - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); WR16(s, 0x420033, 0x3973); WR16(s, 0x420034, s->config.w50); // code 4, log 4 @@ -420,7 +420,7 @@ static int SetCfgIfAgc(struct drx397xD_state *s, struct drx397xD_CfgIfAgc *agc) u16 w0C = agc->w0C; int quot, rem, i, rc = -EINVAL; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if (agc->w04 > 0x3ff) goto exit_rc; @@ -479,7 +479,7 @@ static int SetCfgRfAgc(struct drx397xD_state *s, struct drx397xD_CfgRfAgc *agc) u16 w06 = agc->w06; int rc = -1; - pr_debug("%s %d 0x%x 0x%x\n", __FUNCTION__, agc->d00, w04, w06); + pr_debug("%s %d 0x%x 0x%x\n", __func__, agc->d00, w04, w06); if (w04 > 0x3ff) goto exit_rc; @@ -555,7 +555,7 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s) int lockstat; u32 clk, clk_limit; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); if (s->config.d5C == 0) { EXIT_RC(WR16(s, 0x08200e8, 0x010)); @@ -599,7 +599,7 @@ static int CorrectSysClockDeviation(struct drx397xD_state *s) if (clk - s->config.f_osc * 1000 + clk_limit <= 2 * clk_limit) { s->f_osc = clk; - pr_debug("%s: osc %d %d [Hz]\n", __FUNCTION__, + pr_debug("%s: osc %d %d [Hz]\n", __func__, s->config.f_osc * 1000, clk - s->config.f_osc * 1000); } rc = WR16(s, 0x08200e8, 0); @@ -611,7 +611,7 @@ static int ConfigureMPEGOutput(struct drx397xD_state *s, int type) { int rc, si, bp; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); si = s->config.wA0; if (s->config.w98 == 0) { @@ -647,7 +647,7 @@ static int drx_tune(struct drx397xD_state *s, int rc, df_tuner; int a, b, c, d; - pr_debug("%s %d\n", __FUNCTION__, s->config.d60); + pr_debug("%s %d\n", __func__, s->config.d60); if (s->config.d60 != 2) goto set_tuner; @@ -1124,7 +1124,7 @@ static int drx397x_init(struct dvb_frontend *fe) struct drx397xD_state *s = fe->demodulator_priv; int rc; - pr_debug("%s\n", __FUNCTION__); + pr_debug("%s\n", __func__); s->config.rfagc.d00 = 2; /* 0x7c */ s->config.rfagc.w04 = 0; diff --git a/linux/drivers/media/dvb/frontends/drx397xD.h b/linux/drivers/media/dvb/frontends/drx397xD.h index ddc7a0797..2ad1ea0cc 100644 --- a/linux/drivers/media/dvb/frontends/drx397xD.h +++ b/linux/drivers/media/dvb/frontends/drx397xD.h @@ -122,7 +122,7 @@ extern struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config static inline struct dvb_frontend* drx397xD_attach(const struct drx397xD_config *config, struct i2c_adapter *i2c) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__); + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); return NULL; } #endif /* CONFIG_DVB_DRX397XD */ diff --git a/linux/drivers/media/dvb/frontends/lgs8gl5.c b/linux/drivers/media/dvb/frontends/lgs8gl5.c new file mode 100644 index 000000000..380ae1868 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/lgs8gl5.c @@ -0,0 +1,478 @@ +/* + Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver + + Copyright (C) 2008 Sirius International (Hong Kong) Limited + Timothy Lee <timothy.lee@siriushk.com> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/string.h> +#include <linux/slab.h> +#include "dvb_frontend.h" +#include "lgs8gl5.h" + + +#define REG_RESET 0x02 +#define REG_RESET_OFF 0x01 +#define REG_03 0x03 +#define REG_04 0x04 +#define REG_07 0x07 +#define REG_09 0x09 +#define REG_0A 0x0a +#define REG_0B 0x0b +#define REG_0C 0x0c +#define REG_37 0x37 +#define REG_STRENGTH 0x4b +#define REG_STRENGTH_MASK 0x7f +#define REG_STRENGTH_CARRIER 0x80 +#define REG_INVERSION 0x7c +#define REG_INVERSION_ON 0x80 +#define REG_7D 0x7d +#define REG_7E 0x7e +#define REG_A2 0xa2 +#define REG_STATUS 0xa4 +#define REG_STATUS_SYNC 0x04 +#define REG_STATUS_LOCK 0x01 + + +struct lgs8gl5_state { + struct i2c_adapter *i2c; + const struct lgs8gl5_config *config; + struct dvb_frontend frontend; +}; + + +static int debug; +#define dprintk(args...) \ + do { \ + if (debug) \ + printk(KERN_DEBUG "lgs8gl5: " args); \ + } while (0) + + +/* Writes into demod's register */ +static int +lgs8gl5_write_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + int ret; + u8 buf[] = {reg, data}; + struct i2c_msg msg = { + .addr = state->config->demod_address, + .flags = 0, + .buf = buf, + .len = 2 + }; + + ret = i2c_transfer(state->i2c, &msg, 1); + if (ret != 1) + dprintk("%s: error (reg=0x%02x, val=0x%02x, ret=%i)\n", + __func__, reg, data, ret); + return (ret != 1) ? -1 : 0; +} + + +/* Reads from demod's register */ +static int +lgs8gl5_read_reg(struct lgs8gl5_state *state, u8 reg) +{ + int ret; + u8 b0[] = {reg}; + u8 b1[] = {0}; + struct i2c_msg msg[2] = { + { + .addr = state->config->demod_address, + .flags = 0, + .buf = b0, + .len = 1 + }, + { + .addr = state->config->demod_address, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + } + }; + + ret = i2c_transfer(state->i2c, msg, 2); + if (ret != 2) + return -EIO; + + return b1[0]; +} + + +static int +lgs8gl5_update_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + lgs8gl5_read_reg(state, reg); + lgs8gl5_write_reg(state, reg, data); + return 0; +} + + +/* Writes into alternate device's register */ +/* TODO: Find out what that device is for! */ +static int +lgs8gl5_update_alt_reg(struct lgs8gl5_state *state, u8 reg, u8 data) +{ + int ret; + u8 b0[] = {reg}; + u8 b1[] = {0}; + u8 b2[] = {reg, data}; + struct i2c_msg msg[3] = { + { + .addr = state->config->demod_address + 2, + .flags = 0, + .buf = b0, + .len = 1 + }, + { + .addr = state->config->demod_address + 2, + .flags = I2C_M_RD, + .buf = b1, + .len = 1 + }, + { + .addr = state->config->demod_address + 2, + .flags = 0, + .buf = b2, + .len = 2 + }, + }; + + ret = i2c_transfer(state->i2c, msg, 3); + return (ret != 3) ? -1 : 0; +} + + +static void +lgs8gl5_soft_reset(struct lgs8gl5_state *state) +{ + u8 val; + + dprintk("%s\n", __func__); + + val = lgs8gl5_read_reg(state, REG_RESET); + lgs8gl5_write_reg(state, REG_RESET, val & ~REG_RESET_OFF); + lgs8gl5_write_reg(state, REG_RESET, val | REG_RESET_OFF); + msleep(5); +} + +#if 0 +static int +lgs8gl5_set_inversion(struct lgs8gl5_state *state, int inversion) +{ + u8 val; + + dprintk("%s\n", __func__); + + switch (inversion) { + case INVERSION_AUTO: + return -EOPNOTSUPP; + case INVERSION_ON: + val = lgs8gl5_read_reg(state, REG_INVERSION); + return lgs8gl5_write_reg(state, REG_INVERSION, + val | REG_INVERSION_ON); + case INVERSION_OFF: + val = lgs8gl5_read_reg(state, REG_INVERSION); + return lgs8gl5_write_reg(state, REG_INVERSION, + val & ~REG_INVERSION_ON); + default: + return -EINVAL; + } +} +#endif + +/* Starts demodulation */ +static void +lgs8gl5_start_demod(struct lgs8gl5_state *state) +{ + u8 val; + int n; + + dprintk("%s\n", __func__); + + lgs8gl5_update_alt_reg(state, 0xc2, 0x28); + lgs8gl5_soft_reset(state); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_write_reg(state, REG_09, 0x0e); + lgs8gl5_write_reg(state, REG_0A, 0xe5); + lgs8gl5_write_reg(state, REG_0B, 0x35); + lgs8gl5_write_reg(state, REG_0C, 0x30); + + lgs8gl5_update_reg(state, REG_03, 0x00); + lgs8gl5_update_reg(state, REG_7E, 0x01); + lgs8gl5_update_alt_reg(state, 0xc5, 0x00); + lgs8gl5_update_reg(state, REG_04, 0x02); + lgs8gl5_update_reg(state, REG_37, 0x01); + lgs8gl5_soft_reset(state); + + /* Wait for carrier */ + for (n = 0; n < 10; n++) { + val = lgs8gl5_read_reg(state, REG_STRENGTH); + dprintk("Wait for carrier[%d] 0x%02X\n", n, val); + if (val & REG_STRENGTH_CARRIER) + break; + msleep(4); + } + if (!(val & REG_STRENGTH_CARRIER)) + return; + + /* Wait for lock */ + for (n = 0; n < 20; n++) { + val = lgs8gl5_read_reg(state, REG_STATUS); + dprintk("Wait for lock[%d] 0x%02X\n", n, val); + if (val & REG_STATUS_LOCK) + break; + msleep(12); + } + if (!(val & REG_STATUS_LOCK)) + return; + + lgs8gl5_write_reg(state, REG_7D, lgs8gl5_read_reg(state, REG_A2)); + lgs8gl5_soft_reset(state); +} + + +static int +lgs8gl5_init(struct dvb_frontend *fe) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + lgs8gl5_update_alt_reg(state, 0xc2, 0x28); + lgs8gl5_soft_reset(state); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_update_reg(state, REG_07, 0x10); + lgs8gl5_write_reg(state, REG_09, 0x0e); + lgs8gl5_write_reg(state, REG_0A, 0xe5); + lgs8gl5_write_reg(state, REG_0B, 0x35); + lgs8gl5_write_reg(state, REG_0C, 0x30); + + return 0; +} + + +static int +lgs8gl5_read_status(struct dvb_frontend *fe, fe_status_t *status) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + u8 flags = lgs8gl5_read_reg(state, REG_STATUS); + + *status = 0; + + if ((level & REG_STRENGTH_MASK) > 0) + *status |= FE_HAS_SIGNAL; + if (level & REG_STRENGTH_CARRIER) + *status |= FE_HAS_CARRIER; + if (flags & REG_STATUS_SYNC) + *status |= FE_HAS_SYNC; + if (flags & REG_STATUS_LOCK) + *status |= FE_HAS_LOCK; + + return 0; +} + + +static int +lgs8gl5_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + *ber = 0; + + return 0; +} + + +static int +lgs8gl5_read_signal_strength(struct dvb_frontend *fe, u16 *signal_strength) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + *signal_strength = (level & REG_STRENGTH_MASK) << 8; + + return 0; +} + + +static int +lgs8gl5_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 level = lgs8gl5_read_reg(state, REG_STRENGTH); + *snr = (level & REG_STRENGTH_MASK) << 8; + + return 0; +} + + +static int +lgs8gl5_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + + return 0; +} + + +static int +lgs8gl5_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + + dprintk("%s\n", __func__); + + if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ) + return -EINVAL; + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + /* lgs8gl5_set_inversion(state, p->inversion); */ + + lgs8gl5_start_demod(state); + + return 0; +} + + +static int +lgs8gl5_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + u8 inv = lgs8gl5_read_reg(state, REG_INVERSION); + struct dvb_ofdm_parameters *o = &p->u.ofdm; + + p->inversion = (inv & REG_INVERSION_ON) ? INVERSION_ON : INVERSION_OFF; + + o->code_rate_HP = FEC_1_2; + o->code_rate_LP = FEC_7_8; + o->guard_interval = GUARD_INTERVAL_1_32; + o->transmission_mode = TRANSMISSION_MODE_2K; + o->constellation = QAM_64; + o->hierarchy_information = HIERARCHY_NONE; + o->bandwidth = BANDWIDTH_8_MHZ; + + return 0; +} + + +static int +lgs8gl5_get_tune_settings(struct dvb_frontend *fe, + struct dvb_frontend_tune_settings *fesettings) +{ + fesettings->min_delay_ms = 240; + fesettings->step_size = 0; + fesettings->max_drift = 0; + return 0; +} + + +static void +lgs8gl5_release(struct dvb_frontend *fe) +{ + struct lgs8gl5_state *state = fe->demodulator_priv; + kfree(state); +} + + +static struct dvb_frontend_ops lgs8gl5_ops; + + +struct dvb_frontend* +lgs8gl5_attach(const struct lgs8gl5_config *config, struct i2c_adapter *i2c) +{ + struct lgs8gl5_state *state = NULL; + + dprintk("%s\n", __func__); + + /* Allocate memory for the internal state */ + state = kmalloc(sizeof(struct lgs8gl5_state), GFP_KERNEL); + if (state == NULL) + goto error; + + /* Setup the state */ + state->config = config; + state->i2c = i2c; + + /* Check if the demod is there */ + if (lgs8gl5_read_reg(state, REG_RESET) < 0) + goto error; + + /* Create dvb_frontend */ + memcpy(&state->frontend.ops, &lgs8gl5_ops, + sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + kfree(state); + return NULL; +} +EXPORT_SYMBOL(lgs8gl5_attach); + + +static struct dvb_frontend_ops lgs8gl5_ops = { + .info = { + .name = "Legend Silicon LGS-8GL5 DMB-TH", + .type = FE_OFDM, + .frequency_min = 474000000, + .frequency_max = 858000000, + .frequency_stepsize = 10000, + .frequency_tolerance = 0, + .caps = FE_CAN_FEC_AUTO | + FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | + FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_BANDWIDTH_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER + }, + + .release = lgs8gl5_release, + + .init = lgs8gl5_init, + + .set_frontend = lgs8gl5_set_frontend, + .get_frontend = lgs8gl5_get_frontend, + .get_tune_settings = lgs8gl5_get_tune_settings, + + .read_status = lgs8gl5_read_status, + .read_ber = lgs8gl5_read_ber, + .read_signal_strength = lgs8gl5_read_signal_strength, + .read_snr = lgs8gl5_read_snr, + .read_ucblocks = lgs8gl5_read_ucblocks, +}; + + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); + +MODULE_DESCRIPTION("Legend Silicon LGS-8GL5 DMB-TH Demodulator driver"); +MODULE_AUTHOR("Timothy Lee"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/dvb/frontends/lgs8gl5.h b/linux/drivers/media/dvb/frontends/lgs8gl5.h new file mode 100644 index 000000000..d14176787 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/lgs8gl5.h @@ -0,0 +1,45 @@ +/* + Legend Silicon LGS-8GL5 DMB-TH OFDM demodulator driver + + Copyright (C) 2008 Sirius International (Hong Kong) Limited + Timothy Lee <timothy.lee@siriushk.com> + + 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 LGS8GL5_H +#define LGS8GL5_H + +#include <linux/dvb/frontend.h> + +struct lgs8gl5_config { + /* the demodulator's i2c address */ + u8 demod_address; +}; + +#if defined(CONFIG_DVB_LGS8GL5) || \ + (defined(CONFIG_DVB_LGS8GL5_MODULE) && defined(MODULE)) +extern struct dvb_frontend *lgs8gl5_attach( + const struct lgs8gl5_config *config, struct i2c_adapter *i2c); +#else +static inline struct dvb_frontend *lgs8gl5_attach( + const struct lgs8gl5_config *config, struct i2c_adapter *i2c) { + printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_LGS8GL5 */ + +#endif /* LGS8GL5_H */ diff --git a/linux/drivers/media/dvb/pluto2/pluto2.c b/linux/drivers/media/dvb/pluto2/pluto2.c index d654d872e..cb368e2e0 100644 --- a/linux/drivers/media/dvb/pluto2/pluto2.c +++ b/linux/drivers/media/dvb/pluto2/pluto2.c @@ -242,7 +242,11 @@ static int __devinit pluto_dma_map(struct pluto *pluto) pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf, TS_DMA_BYTES, PCI_DMA_FROMDEVICE); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) return pci_dma_mapping_error(pluto->dma_addr); +#else + return pci_dma_mapping_error(pluto->pdev, pluto->dma_addr); +#endif } static void pluto_dma_unmap(struct pluto *pluto) diff --git a/linux/drivers/media/dvb/ttpci/Kconfig b/linux/drivers/media/dvb/ttpci/Kconfig index 87c973ac6..41b5a988b 100644 --- a/linux/drivers/media/dvb/ttpci/Kconfig +++ b/linux/drivers/media/dvb/ttpci/Kconfig @@ -5,8 +5,6 @@ config TTPCI_EEPROM config DVB_AV7110 tristate "AV7110 cards" depends on DVB_CORE && PCI && I2C - depends on HOTPLUG - select FW_LOADER if !DVB_AV7110_FIRMWARE select TTPCI_EEPROM select VIDEO_SAA7146_VV depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV @@ -127,14 +125,12 @@ config DVB_BUDGET_AV depends on DVB_BUDGET_CORE && I2C select VIDEO_SAA7146_VV depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV - depends on HOTPLUG # dependency of FW_LOADER select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_STV0299 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE select DVB_TDA10021 if !DVB_FE_CUSTOMISE select DVB_TDA10023 if !DVB_FE_CUSTOMISE select DVB_TUA6100 if !DVB_FE_CUSTOMISE - select FW_LOADER help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard diff --git a/linux/drivers/media/dvb/ttusb-dec/Kconfig b/linux/drivers/media/dvb/ttusb-dec/Kconfig index a23cc0aa1..d5f48a310 100644 --- a/linux/drivers/media/dvb/ttusb-dec/Kconfig +++ b/linux/drivers/media/dvb/ttusb-dec/Kconfig @@ -1,8 +1,6 @@ config DVB_TTUSB_DEC tristate "Technotrend/Hauppauge USB DEC devices" depends on DVB_CORE && USB && INPUT - depends on HOTPLUG # due to FW_LOADER - select FW_LOADER select CRC32 help Support for external USB adapters designed by Technotrend and diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 0fdcb19cb..4c233c41f 100644 --- a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1284,11 +1284,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) u8 b1[] = { 0x61 }; u8 *b; char idstring[21]; -#ifndef TTUSB_KERNEL - u8 *firmware = NULL; -#else const u8 *firmware = NULL; -#endif size_t firmware_size = 0; u16 firmware_csum = 0; __be16 firmware_csum_ns; diff --git a/linux/drivers/media/radio/Kconfig b/linux/drivers/media/radio/Kconfig index 01ee71e82..1b41b3f77 100644 --- a/linux/drivers/media/radio/Kconfig +++ b/linux/drivers/media/radio/Kconfig @@ -195,38 +195,6 @@ config RADIO_MAESTRO To compile this driver as a module, choose M here: the module will be called radio-maestro. -config RADIO_MIROPCM20 - tristate "miroSOUND PCM20 radio" - depends on ISA && VIDEO_V4L1 && SOUND_ACI_MIXER - ---help--- - Choose Y here if you have this FM radio card. You also need to say Y - to "ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio)" (in "Sound") - for this to work. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - <file:Documentation/video4linux/API.html>. - - To compile this driver as a module, choose M here: the - module will be called miropcm20. - -config RADIO_MIROPCM20_RDS - tristate "miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)" - depends on RADIO_MIROPCM20 && EXPERIMENTAL - ---help--- - Choose Y here if you want to see RDS/RBDS information like - RadioText, Programme Service name, Clock Time and date, Programme - Type and Traffic Announcement/Programme identification. - - It's not possible to read the raw RDS packets from the device, so - the driver cant provide an V4L interface for this. But the - availability of RDS is reported over V4L by the basic driver - already. Here RDS can be read from files in /dev/v4l/rds. - - To compile this driver as a module, choose M here: the - module will be called miropcm20-rds. - config RADIO_SF16FMI tristate "SF16FMI Radio" depends on ISA && VIDEO_V4L2 diff --git a/linux/drivers/media/radio/Makefile b/linux/drivers/media/radio/Makefile index a30159f6f..7ca71ab96 100644 --- a/linux/drivers/media/radio/Makefile +++ b/linux/drivers/media/radio/Makefile @@ -2,8 +2,6 @@ # Makefile for the kernel character device drivers. # -miropcm20-objs := miropcm20-rds-core.o miropcm20-radio.o - obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o @@ -14,8 +12,6 @@ obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o -obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o -obj-$(CONFIG_RADIO_MIROPCM20_RDS) += miropcm20-rds.o obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o obj-$(CONFIG_RADIO_TRUST) += radio-trust.o diff --git a/linux/drivers/media/radio/dsbr100.c b/linux/drivers/media/radio/dsbr100.c index 92089e705..93a871985 100644 --- a/linux/drivers/media/radio/dsbr100.c +++ b/linux/drivers/media/radio/dsbr100.c @@ -408,15 +408,18 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file) { struct dsbr100_device *radio=video_get_drvdata(video_devdata(file)); + lock_kernel(); radio->users = 1; radio->muted = 1; if (dsbr100_start(radio)<0) { warn("Radio did not start up properly"); radio->users = 0; + unlock_kernel(); return -EIO; } dsbr100_setfreq(radio, radio->curfreq); + unlock_kernel(); return 0; } @@ -446,14 +449,7 @@ static const struct file_operations usb_dsbr100_fops = { .llseek = no_llseek, }; -/* V4L2 interface */ -static struct video_device dsbr100_videodev_template = -{ - .owner = THIS_MODULE, - .name = "D-Link DSB-R 100", - .type = VID_TYPE_TUNER, - .fops = &usb_dsbr100_fops, - .release = video_device_release, +static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -468,6 +464,14 @@ static struct video_device dsbr100_videodev_template = .vidioc_s_input = vidioc_s_input, }; +/* V4L2 interface */ +static struct video_device dsbr100_videodev_template = { + .name = "D-Link DSB-R 100", + .fops = &usb_dsbr100_fops, + .ioctl_ops = &usb_dsbr100_ioctl_ops, + .release = video_device_release, +}; + /* check if the device is present and register with v4l and usb if it is */ static int usb_dsbr100_probe(struct usb_interface *intf, diff --git a/linux/drivers/media/radio/miropcm20-radio.c b/linux/drivers/media/radio/miropcm20-radio.c deleted file mode 100644 index 8dacd5522..000000000 --- a/linux/drivers/media/radio/miropcm20-radio.c +++ /dev/null @@ -1,269 +0,0 @@ -/* Miro PCM20 radio driver for Linux radio support - * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> - * Thanks to Norberto Pellici for the ACI device interface specification - * The API part is based on the radiotrack driver by M. Kirkwood - * This driver relies on the aci mixer (drivers/sound/aci.c) - * Look there for further info... - */ - -/* Revision history: - * - * 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl> - * 2000-09-05 Robert Siemer <Robert.Siemer@gmx.de> - * removed unfinished volume control (maybe adding it later again) - * use OSS-mixer; added stereo control - */ - -/* What ever you think about the ACI, version 0x07 is not very well! - * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono - * conditions... Robert - */ - -#include <linux/module.h> -#include <linux/init.h> -#include "compat.h" -#include <linux/videodev.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> -#include "oss/aci.h" -#include "miropcm20-rds-core.h" - -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -struct pcm20_device { - unsigned long freq; - int muted; - int stereo; -}; - - -static int pcm20_mute(struct pcm20_device *dev, unsigned char mute) -{ - dev->muted = mute; - return aci_write_cmd(ACI_SET_TUNERMUTE, mute); -} - -static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo) -{ - dev->stereo = stereo; - return aci_write_cmd(ACI_SET_TUNERMONO, !stereo); -} - -static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq) -{ - unsigned char freql; - unsigned char freqh; - - dev->freq=freq; - - freq /= 160; - if (!(aci_version==0x07 || aci_version>=0xb0)) - freq /= 10; /* I don't know exactly which version - * needs this hack */ - freql = freq & 0xff; - freqh = freq >> 8; - - aci_rds_cmd(RDS_RESET, NULL, 0); - pcm20_stereo(dev, 1); - - return aci_rw_cmd(ACI_WRITE_TUNE, freql, freqh); -} - -static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal) -{ - /* okay, check for signal, stereo and rds here... */ - int i; - unsigned char buf; - - if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0) - return i; - pr_debug("check_sig: 0x%x\n", i); - if (i & 0x80) { - /* no signal from tuner */ - *flags=0; - *signal=0; - return 0; - } else - *signal=0xffff; - - if ((i=aci_rw_cmd(ACI_READ_TUNERSTEREO, -1, -1))<0) - return i; - if (i & 0x40) { - *flags=0; - } else { - /* stereo */ - *flags=VIDEO_TUNER_STEREO_ON; - /* I can't see stereo, when forced to mono */ - dev->stereo=1; - } - - if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0) - return i; - if (buf & 1) - /* RDS available */ - *flags|=VIDEO_TUNER_RDS_ON; - else - return 0; - - if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0) - return i; - pr_debug("rds-signal: %d\n", buf); - if (buf > 15) { - printk("miropcm20-radio: RX strengths unexpected high...\n"); - buf=15; - } - /* refine signal */ - if ((*signal=SCALE(15, 0xffff, buf))==0) - *signal = 1; - - return 0; -} - -static int pcm20_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *arg) -{ - struct video_device *dev = video_devdata(file); - struct pcm20_device *pcm20 = dev->priv; - int i; - - switch(cmd) - { - case VIDIOCGCAP: - { - struct video_capability *v = arg; - memset(v,0,sizeof(*v)); - v->type=VID_TYPE_TUNER; - strcpy(v->name, "Miro PCM20"); - v->channels=1; - v->audios=1; - return 0; - } - case VIDIOCGTUNER: - { - struct video_tuner *v = arg; - if(v->tuner) /* Only 1 tuner */ - return -EINVAL; - v->rangelow=87*16000; - v->rangehigh=108*16000; - pcm20_getflags(pcm20, &v->flags, &v->signal); - v->flags|=VIDEO_TUNER_LOW; - v->mode=VIDEO_MODE_AUTO; - strcpy(v->name, "FM"); - return 0; - } - case VIDIOCSTUNER: - { - struct video_tuner *v = arg; - if(v->tuner!=0) - return -EINVAL; - /* Only 1 tuner so no setting needed ! */ - return 0; - } - case VIDIOCGFREQ: - { - unsigned long *freq = arg; - *freq = pcm20->freq; - return 0; - } - case VIDIOCSFREQ: - { - unsigned long *freq = arg; - pcm20->freq = *freq; - i=pcm20_setfreq(pcm20, pcm20->freq); - pr_debug("First view (setfreq): 0x%x\n", i); - return i; - } - case VIDIOCGAUDIO: - { - struct video_audio *v = arg; - memset(v,0, sizeof(*v)); - v->flags=VIDEO_AUDIO_MUTABLE; - if (pcm20->muted) - v->flags|=VIDEO_AUDIO_MUTE; - v->mode=VIDEO_SOUND_STEREO; - if (pcm20->stereo) - v->mode|=VIDEO_SOUND_MONO; - /* v->step=2048; */ - strcpy(v->name, "Radio"); - return 0; - } - case VIDIOCSAUDIO: - { - struct video_audio *v = arg; - if(v->audio) - return -EINVAL; - - pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE)); - if(v->flags&VIDEO_SOUND_MONO) - pcm20_stereo(pcm20, 0); - if(v->flags&VIDEO_SOUND_STEREO) - pcm20_stereo(pcm20, 1); - - return 0; - } - default: - return -ENOIOCTLCMD; - } -} - -static int pcm20_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return video_usercopy(inode, file, cmd, arg, pcm20_do_ioctl); -} - -static struct pcm20_device pcm20_unit = { - .freq = 87*16000, - .muted = 1, -}; - -static const struct file_operations pcm20_fops = { - .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, - .ioctl = pcm20_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = v4l_compat_ioctl32, -#endif - .llseek = no_llseek, -}; - -static struct video_device pcm20_radio = { - .owner = THIS_MODULE, - .name = "Miro PCM 20 radio", - .type = VID_TYPE_TUNER, - .fops = &pcm20_fops, - .priv = &pcm20_unit -}; - -static int __init pcm20_init(void) -{ - if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1) - goto video_register_device; - - if(attach_aci_rds()<0) - goto attach_aci_rds; - - printk(KERN_INFO "Miro PCM20 radio card driver.\n"); - - return 0; - - attach_aci_rds: - video_unregister_device(&pcm20_radio); - video_register_device: - return -EINVAL; -} - -MODULE_AUTHOR("Ruurd Reitsma"); -MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card."); -MODULE_LICENSE("GPL"); - -static void __exit pcm20_cleanup(void) -{ - unload_aci_rds(); - video_unregister_device(&pcm20_radio); -} - -module_init(pcm20_init); -module_exit(pcm20_cleanup); diff --git a/linux/drivers/media/radio/miropcm20-rds-core.c b/linux/drivers/media/radio/miropcm20-rds-core.c deleted file mode 100644 index e18e2a4a8..000000000 --- a/linux/drivers/media/radio/miropcm20-rds-core.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Many thanks to Fred Seidel <seidel@metabox.de>, the - * designer of the RDS decoder hardware. With his help - * I was able to code this driver. - * Thanks also to Norberto Pellicci, Dominic Mounteney - * <DMounteney@pinnaclesys.com> and www.teleauskunft.de - * for good hints on finding Fred. It was somewhat hard - * to locate him here in Germany... [: - * - * Revision history: - * - * 2000-08-09 Robert Siemer <Robert.Siemer@gmx.de> - * RDS support for MiroSound PCM20 radio - */ - -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/string.h> -#include <linux/init.h> -#include <linux/slab.h> -#include "compat.h" -#include <linux/mutex.h> - -#include <asm/io.h> -#include "oss/aci.h" -#include "miropcm20-rds-core.h" - -#define DEBUG 0 - -static struct mutex aci_rds_mutex; - -#define RDS_DATASHIFT 2 /* Bit 2 */ -#define RDS_DATAMASK (1 << RDS_DATASHIFT) -#define RDS_BUSYMASK 0x10 /* Bit 4 */ -#define RDS_CLOCKMASK 0x08 /* Bit 3 */ - -#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1) - - -#if DEBUG -static void print_matrix(char array[], unsigned int length) -{ - int i, j; - - for (i=0; i<length; i++) { - printk(KERN_DEBUG "aci-rds: "); - for (j=7; j>=0; j--) { - printk("%d", (array[i] >> j) & 0x1); - } - if (i%8 == 0) - printk(" byte-border\n"); - else - printk("\n"); - } -} -#endif /* DEBUG */ - -static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size) -{ - int i; - - if (size != 8) - return -1; - for (i = 7; i >= 0; i--) - sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0; - sendbuffer[0] |= RDS_CLOCKMASK; - - return 0; -} - -static int rds_waitread(void) -{ - unsigned char byte; - int i=2000; - - do { - byte=inb(RDS_REGISTER); - i--; - } - while ((byte & RDS_BUSYMASK) && i); - - if (i) { - #if DEBUG - printk(KERN_DEBUG "rds_waitread()"); - print_matrix(&byte, 1); - #endif - return (byte); - } else { - printk(KERN_WARNING "aci-rds: rds_waitread() timeout...\n"); - return -1; - } -} - -/* don't use any ..._nowait() function if you are not sure what you do... */ - -static inline void rds_rawwrite_nowait(unsigned char byte) -{ - #if DEBUG - printk(KERN_DEBUG "rds_rawwrite()"); - print_matrix(&byte, 1); - #endif - outb(byte, RDS_REGISTER); -} - -static int rds_rawwrite(unsigned char byte) -{ - if (rds_waitread() >= 0) { - rds_rawwrite_nowait(byte); - return 0; - } else - return -1; -} - -static int rds_write(unsigned char cmd) -{ - unsigned char sendbuffer[8]; - int i; - - if (byte2trans(cmd, sendbuffer, 8) != 0){ - return -1; - } else { - for (i=0; i<8; i++) { - rds_rawwrite(sendbuffer[i]); - } - } - return 0; -} - -static int rds_readcycle_nowait(void) -{ - rds_rawwrite_nowait(0); - return rds_waitread(); -} - -static int rds_readcycle(void) -{ - if (rds_rawwrite(0) < 0) - return -1; - return rds_waitread(); -} - -static int rds_read(unsigned char databuffer[], int datasize) -{ - #define READSIZE (8*datasize) - - int i,j; - - if (datasize < 1) /* nothing to read */ - return 0; - - /* to be able to use rds_readcycle_nowait() - I have to waitread() here */ - if (rds_waitread() < 0) - return -1; - - memset(databuffer, 0, datasize); - - for (i=0; i< READSIZE; i++) - if((j=rds_readcycle_nowait()) < 0) { - return -1; - } else { - databuffer[i/8]|=(RDS_DATA(j) << (7-(i%8))); - } - - return 0; -} - -static int rds_ack(void) -{ - int i=rds_readcycle(); - - if (i < 0) - return -1; - if (i & RDS_DATAMASK) { - return 0; /* ACK */ - } else { - printk(KERN_DEBUG "aci-rds: NACK\n"); - return 1; /* NACK */ - } -} - -int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize) -{ - int ret; - - if (mutex_lock_interruptible(&aci_rds_mutex)) - return -EINTR; - - rds_write(cmd); - - /* RDS_RESET doesn't need further processing */ - if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize))) - ret = -1; - else - ret = 0; - - mutex_unlock(&aci_rds_mutex); - - return ret; -} -EXPORT_SYMBOL(aci_rds_cmd); - -int __init attach_aci_rds(void) -{ - mutex_init(&aci_rds_mutex); - return 0; -} - -void __exit unload_aci_rds(void) -{ -} -MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/radio/miropcm20-rds-core.h b/linux/drivers/media/radio/miropcm20-rds-core.h deleted file mode 100644 index aeb5761f0..000000000 --- a/linux/drivers/media/radio/miropcm20-rds-core.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _MIROPCM20_RDS_CORE_H_ -#define _MIROPCM20_RDS_CORE_H_ - -extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize); - -#define RDS_STATUS 0x01 -#define RDS_STATIONNAME 0x02 -#define RDS_TEXT 0x03 -#define RDS_ALTFREQ 0x04 -#define RDS_TIMEDATE 0x05 -#define RDS_PI_CODE 0x06 -#define RDS_PTYTATP 0x07 -#define RDS_RESET 0x08 -#define RDS_RXVALUE 0x09 - -extern void __exit unload_aci_rds(void); -extern int __init attach_aci_rds(void); - -#endif /* _MIROPCM20_RDS_CORE_H_ */ diff --git a/linux/drivers/media/radio/miropcm20-rds.c b/linux/drivers/media/radio/miropcm20-rds.c deleted file mode 100644 index af90cdcf2..000000000 --- a/linux/drivers/media/radio/miropcm20-rds.c +++ /dev/null @@ -1,140 +0,0 @@ -/* MiroSOUND PCM20 radio rds interface driver - * (c) 2001 Robert Siemer <Robert.Siemer@gmx.de> - * Thanks to Fred Seidel. See miropcm20-rds-core.c for further information. - */ - -/* Revision history: - * - * 2001-04-18 Robert Siemer <Robert.Siemer@gmx.de> - * separate file for user interface driver - */ - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/smp_lock.h> -#include <linux/fs.h> -#include <linux/miscdevice.h> -#include <linux/delay.h> -#include <asm/uaccess.h> -#include "miropcm20-rds-core.h" - -static char * text_buffer; -static int rds_users; - - -static int rds_f_open(struct inode *in, struct file *fi) -{ - if (rds_users) - return -EBUSY; - - lock_kernel(); - rds_users++; - if ((text_buffer=kmalloc(66, GFP_KERNEL)) == 0) { - rds_users--; - printk(KERN_NOTICE "aci-rds: Out of memory by open()...\n"); - unlock_kernel(); - return -ENOMEM; - } - - unlock_kernel(); - return 0; -} - -static int rds_f_release(struct inode *in, struct file *fi) -{ - kfree(text_buffer); - - rds_users--; - return 0; -} - -static void print_matrix(char *ch, char out[]) -{ - int j; - - for (j=7; j>=0; j--) { - out[7-j] = ((*ch >> j) & 0x1) + '0'; - } -} - -static ssize_t rds_f_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) -{ -// i = sprintf(text_buffer, "length: %d, offset: %d\n", length, *offset); - - char c; - char bits[8]; - - msleep(2000); - aci_rds_cmd(RDS_STATUS, &c, 1); - print_matrix(&c, bits); - if (copy_to_user(buffer, bits, 8)) - return -EFAULT; - -/* if ((c >> 3) & 1) { - aci_rds_cmd(RDS_STATIONNAME, text_buffer+1, 8); - text_buffer[0] = ' ' ; - text_buffer[9] = '\n'; - return copy_to_user(buffer+8, text_buffer, 10) ? -EFAULT: 18; - } -*/ -/* if ((c >> 6) & 1) { - aci_rds_cmd(RDS_PTYTATP, &c, 1); - if ( c & 1) - sprintf(text_buffer, " M"); - else - sprintf(text_buffer, " S"); - if ((c >> 1) & 1) - sprintf(text_buffer+2, " TA"); - else - sprintf(text_buffer+2, " --"); - if ((c >> 7) & 1) - sprintf(text_buffer+5, " TP"); - else - sprintf(text_buffer+5, " --"); - sprintf(text_buffer+8, " %2d\n", (c >> 2) & 0x1f); - return copy_to_user(buffer+8, text_buffer, 12) ? -EFAULT: 20; - } -*/ - - if ((c >> 4) & 1) { - aci_rds_cmd(RDS_TEXT, text_buffer, 65); - text_buffer[0] = ' ' ; - text_buffer[65] = '\n'; - return copy_to_user(buffer+8, text_buffer,66) ? -EFAULT : 66+8; - } else { - put_user('\n', buffer+8); - return 9; - } -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) -static const struct file_operations rds_fops = { -#else -static struct file_operations rds_fops = { -#endif - .owner = THIS_MODULE, - .read = rds_f_read, - .open = rds_f_open, - .release = rds_f_release -}; - -static struct miscdevice rds_miscdev = { - .minor = MISC_DYNAMIC_MINOR, - .name = "radiotext", - .fops = &rds_fops, -}; - -static int __init miropcm20_rds_init(void) -{ - return misc_register(&rds_miscdev); -} - -static void __exit miropcm20_rds_cleanup(void) -{ - misc_deregister(&rds_miscdev); -} - -module_init(miropcm20_rds_init); -module_exit(miropcm20_rds_cleanup); -MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/radio/radio-aimslab.c b/linux/drivers/media/radio/radio-aimslab.c index 4b133820e..516677a98 100644 --- a/linux/drivers/media/radio/radio-aimslab.c +++ b/linux/drivers/media/radio/radio-aimslab.c @@ -390,12 +390,7 @@ static const struct file_operations rtrack_fops = { .llseek = no_llseek, }; -static struct video_device rtrack_radio= -{ - .owner = THIS_MODULE, - .name = "RadioTrack radio", - .type = VID_TYPE_TUNER, - .fops = &rtrack_fops, +static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -410,6 +405,12 @@ static struct video_device rtrack_radio= .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device rtrack_radio = { + .name = "RadioTrack radio", + .fops = &rtrack_fops, + .ioctl_ops = &rtrack_ioctl_ops, +}; + static int __init rtrack_init(void) { if(io==-1) diff --git a/linux/drivers/media/radio/radio-aztech.c b/linux/drivers/media/radio/radio-aztech.c index 124df79a0..8adb1b003 100644 --- a/linux/drivers/media/radio/radio-aztech.c +++ b/linux/drivers/media/radio/radio-aztech.c @@ -354,12 +354,7 @@ static const struct file_operations aztech_fops = { .llseek = no_llseek, }; -static struct video_device aztech_radio= -{ - .owner = THIS_MODULE, - .name = "Aztech radio", - .type = VID_TYPE_TUNER, - .fops = &aztech_fops, +static const struct v4l2_ioctl_ops aztech_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -374,6 +369,12 @@ static struct video_device aztech_radio= .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device aztech_radio = { + .name = "Aztech radio", + .fops = &aztech_fops, + .ioctl_ops = &aztech_ioctl_ops, +}; + module_param_named(debug,aztech_radio.debug, int, 0644); MODULE_PARM_DESC(debug,"activates debug info"); diff --git a/linux/drivers/media/radio/radio-cadet.c b/linux/drivers/media/radio/radio-cadet.c index 88e6502af..6588f0cd3 100644 --- a/linux/drivers/media/radio/radio-cadet.c +++ b/linux/drivers/media/radio/radio-cadet.c @@ -600,12 +600,7 @@ static const struct file_operations cadet_fops = { .llseek = no_llseek, }; -static struct video_device cadet_radio= -{ - .owner = THIS_MODULE, - .name = "Cadet radio", - .type = VID_TYPE_TUNER, - .fops = &cadet_fops, +static const struct v4l2_ioctl_ops cadet_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -620,6 +615,12 @@ static struct video_device cadet_radio= .vidioc_s_input = vidioc_s_input, }; +static struct video_device cadet_radio = { + .name = "Cadet radio", + .fops = &cadet_fops, + .ioctl_ops = &cadet_ioctl_ops, +}; + #ifdef CONFIG_PNP static struct pnp_device_id cadet_pnp_devices[] = { diff --git a/linux/drivers/media/radio/radio-gemtek-pci.c b/linux/drivers/media/radio/radio-gemtek-pci.c index bf2704841..efee362c7 100644 --- a/linux/drivers/media/radio/radio-gemtek-pci.c +++ b/linux/drivers/media/radio/radio-gemtek-pci.c @@ -376,11 +376,7 @@ static const struct file_operations gemtek_pci_fops = { .llseek = no_llseek, }; -static struct video_device vdev_template = { - .owner = THIS_MODULE, - .name = "Gemtek PCI Radio", - .type = VID_TYPE_TUNER, - .fops = &gemtek_pci_fops, +static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -395,6 +391,12 @@ static struct video_device vdev_template = { .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device vdev_template = { + .name = "Gemtek PCI Radio", + .fops = &gemtek_pci_fops, + .ioctl_ops = &gemtek_pci_ioctl_ops, +}; + static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id ) { struct gemtek_pci_card *card; diff --git a/linux/drivers/media/radio/radio-gemtek.c b/linux/drivers/media/radio/radio-gemtek.c index 3f77c0b57..bf1837ab2 100644 --- a/linux/drivers/media/radio/radio-gemtek.c +++ b/linux/drivers/media/radio/radio-gemtek.c @@ -554,11 +554,7 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) return 0; } -static struct video_device gemtek_radio = { - .owner = THIS_MODULE, - .name = "GemTek Radio card", - .type = VID_TYPE_TUNER, - .fops = &gemtek_fops, +static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -573,6 +569,12 @@ static struct video_device gemtek_radio = { .vidioc_s_ctrl = vidioc_s_ctrl }; +static struct video_device gemtek_radio = { + .name = "GemTek Radio card", + .fops = &gemtek_fops, + .ioctl_ops = &gemtek_ioctl_ops, +}; + /* * Initialization / cleanup related stuff. */ diff --git a/linux/drivers/media/radio/radio-maestro.c b/linux/drivers/media/radio/radio-maestro.c index 00b6cc174..3b382e2b3 100644 --- a/linux/drivers/media/radio/radio-maestro.c +++ b/linux/drivers/media/radio/radio-maestro.c @@ -356,10 +356,7 @@ static u16 __devinit radio_power_on(struct radio_device *dev) return (ofreq == radio_bits_get(dev)); } -static struct video_device maestro_radio = { - .name = "Maestro radio", - .type = VID_TYPE_TUNER, - .fops = &maestro_fops, +static const struct v4l2_ioctl_ops maestro_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -374,6 +371,12 @@ static struct video_device maestro_radio = { .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device maestro_radio = { + .name = "Maestro radio", + .fops = &maestro_fops, + .ioctl_ops = &maestro_ioctl_ops, +}; + static int __devinit maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { diff --git a/linux/drivers/media/radio/radio-maxiradio.c b/linux/drivers/media/radio/radio-maxiradio.c index 612c71fed..0f6bbd81b 100644 --- a/linux/drivers/media/radio/radio-maxiradio.c +++ b/linux/drivers/media/radio/radio-maxiradio.c @@ -375,13 +375,7 @@ static int vidioc_s_ctrl (struct file *file, void *priv, return -EINVAL; } -static struct video_device maxiradio_radio = -{ - .owner = THIS_MODULE, - .name = "Maxi Radio FM2000 radio", - .type = VID_TYPE_TUNER, - .fops = &maxiradio_fops, - +static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -396,6 +390,12 @@ static struct video_device maxiradio_radio = .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device maxiradio_radio = { + .name = "Maxi Radio FM2000 radio", + .fops = &maxiradio_fops, + .ioctl_ops = &maxiradio_ioctl_ops, +}; + static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { if(!request_region(pci_resource_start(pdev, 0), diff --git a/linux/drivers/media/radio/radio-rtrack2.c b/linux/drivers/media/radio/radio-rtrack2.c index 3936b15e8..31d6eabbb 100644 --- a/linux/drivers/media/radio/radio-rtrack2.c +++ b/linux/drivers/media/radio/radio-rtrack2.c @@ -296,12 +296,7 @@ static const struct file_operations rtrack2_fops = { .llseek = no_llseek, }; -static struct video_device rtrack2_radio= -{ - .owner = THIS_MODULE, - .name = "RadioTrack II radio", - .type = VID_TYPE_TUNER, - .fops = &rtrack2_fops, +static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -316,6 +311,12 @@ static struct video_device rtrack2_radio= .vidioc_s_input = vidioc_s_input, }; +static struct video_device rtrack2_radio = { + .name = "RadioTrack II radio", + .fops = &rtrack2_fops, + .ioctl_ops = &rtrack2_ioctl_ops, +}; + static int __init rtrack2_init(void) { if(io==-1) diff --git a/linux/drivers/media/radio/radio-sf16fmi.c b/linux/drivers/media/radio/radio-sf16fmi.c index 5a1c231df..d4433b6a3 100644 --- a/linux/drivers/media/radio/radio-sf16fmi.c +++ b/linux/drivers/media/radio/radio-sf16fmi.c @@ -296,12 +296,7 @@ static const struct file_operations fmi_fops = { .llseek = no_llseek, }; -static struct video_device fmi_radio= -{ - .owner = THIS_MODULE, - .name = "SF16FMx radio", - .type = VID_TYPE_TUNER, - .fops = &fmi_fops, +static const struct v4l2_ioctl_ops fmi_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -316,6 +311,12 @@ static struct video_device fmi_radio= .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device fmi_radio = { + .name = "SF16FMx radio", + .fops = &fmi_fops, + .ioctl_ops = &fmi_ioctl_ops, +}; + /* ladis: this is my card. does any other types exist? */ static struct isapnp_device_id id_table[] __devinitdata = { { ISAPNP_ANY_ID, ISAPNP_ANY_ID, diff --git a/linux/drivers/media/radio/radio-sf16fmr2.c b/linux/drivers/media/radio/radio-sf16fmr2.c index 555b97a6c..7b7748561 100644 --- a/linux/drivers/media/radio/radio-sf16fmr2.c +++ b/linux/drivers/media/radio/radio-sf16fmr2.c @@ -412,12 +412,7 @@ static const struct file_operations fmr2_fops = { .llseek = no_llseek, }; -static struct video_device fmr2_radio= -{ - .owner = THIS_MODULE, - .name = "SF16FMR2 radio", - . type = VID_TYPE_TUNER, - .fops = &fmr2_fops, +static const struct v4l2_ioctl_ops fmr2_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -432,6 +427,12 @@ static struct video_device fmr2_radio= .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device fmr2_radio = { + .name = "SF16FMR2 radio", + .fops = &fmr2_fops, + .ioctl_ops = &fmr2_ioctl_ops, +}; + static int __init fmr2_init(void) { fmr2_unit.port = io; diff --git a/linux/drivers/media/radio/radio-si470x.c b/linux/drivers/media/radio/radio-si470x.c index 110989cac..3b1f630a9 100644 --- a/linux/drivers/media/radio/radio-si470x.c +++ b/linux/drivers/media/radio/radio-si470x.c @@ -1079,6 +1079,7 @@ static int si470x_fops_open(struct inode *inode, struct file *file) struct si470x_device *radio = video_get_drvdata(video_devdata(file)); int retval; + lock_kernel(); radio->users++; retval = usb_autopm_get_interface(radio->intf); @@ -1095,6 +1096,7 @@ static int si470x_fops_open(struct inode *inode, struct file *file) } done: + unlock_kernel(); return retval; } @@ -1591,15 +1593,7 @@ done: return retval; } - -/* - * si470x_viddev_tamples - video device interface - */ -static struct video_device si470x_viddev_template = { - .fops = &si470x_fops, - .name = DRIVER_NAME, - .type = VID_TYPE_TUNER, - .release = video_device_release, +static const struct v4l2_ioctl_ops si470x_ioctl_ops = { .vidioc_querycap = si470x_vidioc_querycap, .vidioc_g_input = si470x_vidioc_g_input, .vidioc_s_input = si470x_vidioc_s_input, @@ -1613,7 +1607,16 @@ static struct video_device si470x_viddev_template = { .vidioc_g_frequency = si470x_vidioc_g_frequency, .vidioc_s_frequency = si470x_vidioc_s_frequency, .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek, - .owner = THIS_MODULE, +}; + +/* + * si470x_viddev_tamples - video device interface + */ +static struct video_device si470x_viddev_template = { + .fops = &si470x_fops, + .ioctl_ops = &si470x_ioctl_ops, + .name = DRIVER_NAME, + .release = video_device_release, }; diff --git a/linux/drivers/media/radio/radio-terratec.c b/linux/drivers/media/radio/radio-terratec.c index f88ab2816..768582f53 100644 --- a/linux/drivers/media/radio/radio-terratec.c +++ b/linux/drivers/media/radio/radio-terratec.c @@ -368,12 +368,7 @@ static const struct file_operations terratec_fops = { .llseek = no_llseek, }; -static struct video_device terratec_radio= -{ - .owner = THIS_MODULE, - .name = "TerraTec ActiveRadio", - .type = VID_TYPE_TUNER, - .fops = &terratec_fops, +static const struct v4l2_ioctl_ops terratec_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -388,6 +383,12 @@ static struct video_device terratec_radio= .vidioc_s_input = vidioc_s_input, }; +static struct video_device terratec_radio = { + .name = "TerraTec ActiveRadio", + .fops = &terratec_fops, + .ioctl_ops = &terratec_ioctl_ops, +}; + static int __init terratec_init(void) { if(io==-1) diff --git a/linux/drivers/media/radio/radio-trust.c b/linux/drivers/media/radio/radio-trust.c index 3e72b1c6c..648007027 100644 --- a/linux/drivers/media/radio/radio-trust.c +++ b/linux/drivers/media/radio/radio-trust.c @@ -351,12 +351,7 @@ static const struct file_operations trust_fops = { .llseek = no_llseek, }; -static struct video_device trust_radio= -{ - .owner = THIS_MODULE, - .name = "Trust FM Radio", - .type = VID_TYPE_TUNER, - .fops = &trust_fops, +static const struct v4l2_ioctl_ops trust_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -371,6 +366,12 @@ static struct video_device trust_radio= .vidioc_s_input = vidioc_s_input, }; +static struct video_device trust_radio = { + .name = "Trust FM Radio", + .fops = &trust_fops, + .ioctl_ops = &trust_ioctl_ops, +}; + static int __init trust_init(void) { if(io == -1) { diff --git a/linux/drivers/media/radio/radio-typhoon.c b/linux/drivers/media/radio/radio-typhoon.c index b076936dd..fa66168d7 100644 --- a/linux/drivers/media/radio/radio-typhoon.c +++ b/linux/drivers/media/radio/radio-typhoon.c @@ -346,12 +346,7 @@ static const struct file_operations typhoon_fops = { .llseek = no_llseek, }; -static struct video_device typhoon_radio = -{ - .owner = THIS_MODULE, - .name = "Typhoon Radio", - .type = VID_TYPE_TUNER, - .fops = &typhoon_fops, +static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -366,6 +361,12 @@ static struct video_device typhoon_radio = .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device typhoon_radio = { + .name = "Typhoon Radio", + .fops = &typhoon_fops, + .ioctl_ops = &typhoon_ioctl_ops, +}; + #ifdef CONFIG_RADIO_TYPHOON_PROC_FS static int typhoon_proc_show(struct seq_file *m, void *v) diff --git a/linux/drivers/media/radio/radio-zoltrix.c b/linux/drivers/media/radio/radio-zoltrix.c index 0bcc38b46..ef6d6a66f 100644 --- a/linux/drivers/media/radio/radio-zoltrix.c +++ b/linux/drivers/media/radio/radio-zoltrix.c @@ -409,12 +409,7 @@ static const struct file_operations zoltrix_fops = .llseek = no_llseek, }; -static struct video_device zoltrix_radio = -{ - .owner = THIS_MODULE, - .name = "Zoltrix Radio Plus", - .type = VID_TYPE_TUNER, - .fops = &zoltrix_fops, +static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -429,6 +424,12 @@ static struct video_device zoltrix_radio = .vidioc_s_ctrl = vidioc_s_ctrl, }; +static struct video_device zoltrix_radio = { + .name = "Zoltrix Radio Plus", + .fops = &zoltrix_fops, + .ioctl_ops = &zoltrix_ioctl_ops, +}; + static int __init zoltrix_init(void) { if (io == -1) { diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig index 2a747db6d..7b2925808 100644 --- a/linux/drivers/media/video/Kconfig +++ b/linux/drivers/media/video/Kconfig @@ -34,6 +34,7 @@ config VIDEOBUF_DVB select VIDEOBUF_GEN config VIDEO_BTCX + depends on PCI tristate config VIDEO_IR @@ -487,17 +488,6 @@ config VIDEO_PMS To compile this driver as a module, choose M here: the module will be called pms. -config VIDEO_PLANB - tristate "PlanB Video-In on PowerMac" - depends on PPC_PMAC && VIDEO_V4L1 && BROKEN - help - PlanB is the V4L driver for the PowerMac 7x00/8x00 series video - input hardware. If you want to experiment with this, say Y. - Otherwise, or if you don't understand a word, say N. See - <http://www.cpu.lu/~mlan/linux/dev/planb.html> for more info. - - Saying M will compile this driver as a module (planb). - config VIDEO_BWQCAM tristate "Quickcam BW Video For Linux" depends on PARPORT && VIDEO_V4L1 @@ -589,13 +579,6 @@ config VIDEO_SAA5249 To compile this driver as a module, choose M here: the module will be called saa5249. -config TUNER_3036 - tristate "SAB3036 tuner" - depends on I2C && VIDEO_V4L1 - help - Say Y here to include support for Philips SAB3036 compatible tuners. - If in doubt, say N. - config VIDEO_VINO tristate "SGI Vino Video For Linux (EXPERIMENTAL)" depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2 @@ -641,7 +624,7 @@ config VIDEO_ZORAN_ZR36060 depends on VIDEO_ZORAN help Say Y to support Zoran boards based on 36060 chips. - This includes Iomega Bus, Pinnacle DC10, Linux media Labs 33 + This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33 and 33 R10 and AverMedia 6 boards. config VIDEO_ZORAN_BUZ @@ -719,21 +702,6 @@ config VIDEO_MXB To compile this driver as a module, choose M here: the module will be called mxb. -config VIDEO_DPC - tristate "Philips-Semiconductors 'dpc7146 demonstration board'" - depends on PCI && VIDEO_V4L1 && I2C - select VIDEO_SAA7146_VV - select VIDEO_SAA7111 if VIDEO_HELPER_CHIPS_AUTO - ---help--- - This is a video4linux driver for the 'dpc7146 demonstration - board' by Philips-Semiconductors. It's the reference design - for SAA7146 bases boards, so if you have some unsupported - saa7146 based, analog video card, chances are good that it - will work with this skeleton driver. - - To compile this driver as a module, choose M here: the - module will be called dpc7146. - config VIDEO_HEXIUM_ORION tristate "Hexium HV-PCI6 and Orion frame grabber" depends on PCI && VIDEO_V4L2 && I2C @@ -795,6 +763,70 @@ config VIDEO_CAFE_CCIC CMOS camera controller. This is the controller found on first- generation OLPC systems. +config SOC_CAMERA + tristate "SoC camera support" + depends on VIDEO_V4L2 && HAS_DMA + select VIDEOBUF_GEN + help + SoC Camera is a common API to several cameras, not connecting + over a bus like PCI or USB. For example some i2c camera connected + directly to the data bus of an SoC. + +config SOC_CAMERA_MT9M001 + tristate "mt9m001 support" + depends on SOC_CAMERA && I2C + select GPIO_PCA953X if MT9M001_PCA9536_SWITCH + help + This driver supports MT9M001 cameras from Micron, monochrome + and colour models. + +config MT9M001_PCA9536_SWITCH + bool "pca9536 datawidth switch for mt9m001" + depends on SOC_CAMERA_MT9M001 && GENERIC_GPIO + help + Select this if your MT9M001 camera uses a PCA9536 I2C GPIO + extender to switch between 8 and 10 bit datawidth modes + +config SOC_CAMERA_MT9M111 + tristate "mt9m111 support" + depends on SOC_CAMERA && I2C + help + This driver supports MT9M111 cameras from Micron + +config SOC_CAMERA_MT9V022 + tristate "mt9v022 support" + depends on SOC_CAMERA && I2C + select GPIO_PCA953X if MT9V022_PCA9536_SWITCH + help + This driver supports MT9V022 cameras from Micron + +config MT9V022_PCA9536_SWITCH + bool "pca9536 datawidth switch for mt9v022" + depends on SOC_CAMERA_MT9V022 && GENERIC_GPIO + help + Select this if your MT9V022 camera uses a PCA9536 I2C GPIO + extender to switch between 8 and 10 bit datawidth modes + +config SOC_CAMERA_PLATFORM + tristate "platform camera support" + depends on SOC_CAMERA + help + This is a generic SoC camera platform driver, useful for testing + +config VIDEO_PXA27x + tristate "PXA27x Quick Capture Interface driver" + depends on VIDEO_DEV && PXA27x && SOC_CAMERA + select VIDEOBUF_DMA_SG + ---help--- + This is a v4l2 driver for the PXA27x Quick Capture Interface + +config VIDEO_SH_MOBILE_CEU + tristate "SuperH Mobile CEU Interface driver" + depends on VIDEO_DEV && SOC_CAMERA + select VIDEOBUF_DMA_CONTIG + ---help--- + This is a v4l2 driver for the SuperH Mobile CEU Interface + # # USB Multimedia device configuration # @@ -833,8 +865,7 @@ config VIDEO_OVCAMCHIP config USB_W9968CF tristate "USB W996[87]CF JPEG Dual Mode Camera support" - depends on VIDEO_V4L1 && I2C - select VIDEO_OVCAMCHIP + depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP ---help--- Say Y here if you want support for cameras based on OV681 or Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips. @@ -925,64 +956,4 @@ config USB_S2255 endif # V4L_USB_DRIVERS -config SOC_CAMERA - tristate "SoC camera support" - depends on VIDEO_V4L2 && HAS_DMA - select VIDEOBUF_GEN - help - SoC Camera is a common API to several cameras, not connecting - over a bus like PCI or USB. For example some i2c camera connected - directly to the data bus of an SoC. - -config SOC_CAMERA_MT9M001 - tristate "mt9m001 support" - depends on SOC_CAMERA && I2C - select GPIO_PCA953X if MT9M001_PCA9536_SWITCH - help - This driver supports MT9M001 cameras from Micron, monochrome - and colour models. - -config MT9M001_PCA9536_SWITCH - bool "pca9536 datawidth switch for mt9m001" - depends on SOC_CAMERA_MT9M001 && GENERIC_GPIO - help - Select this if your MT9M001 camera uses a PCA9536 I2C GPIO - extender to switch between 8 and 10 bit datawidth modes - -config SOC_CAMERA_MT9V022 - tristate "mt9v022 support" - depends on SOC_CAMERA && I2C - select GPIO_PCA953X if MT9V022_PCA9536_SWITCH - help - This driver supports MT9V022 cameras from Micron - -config MT9V022_PCA9536_SWITCH - bool "pca9536 datawidth switch for mt9v022" - depends on SOC_CAMERA_MT9V022 && GENERIC_GPIO - help - Select this if your MT9V022 camera uses a PCA9536 I2C GPIO - extender to switch between 8 and 10 bit datawidth modes - -config SOC_CAMERA_PLATFORM - tristate "platform camera support" - depends on SOC_CAMERA - help - This is a generic SoC camera platform driver, useful for testing - -config VIDEO_PXA27x - tristate "PXA27x Quick Capture Interface driver" - depends on VIDEO_DEV && PXA27x - select SOC_CAMERA - select VIDEOBUF_DMA_SG - ---help--- - This is a v4l2 driver for the PXA27x Quick Capture Interface - -config VIDEO_SH_MOBILE_CEU - tristate "SuperH Mobile CEU Interface driver" - depends on VIDEO_DEV - select SOC_CAMERA - select VIDEOBUF_DMA_CONTIG - ---help--- - This is a v4l2 driver for the SuperH Mobile CEU Interface - endif # VIDEO_CAPTURE_DRIVERS diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile index a0240a105..5656cfecf 100644 --- a/linux/drivers/media/video/Makefile +++ b/linux/drivers/media/video/Makefile @@ -58,7 +58,6 @@ obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o obj-$(CONFIG_VIDEO_PMS) += pms.o -obj-$(CONFIG_VIDEO_PLANB) += planb.o obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o obj-$(CONFIG_VIDEO_STRADIS) += stradis.o obj-$(CONFIG_VIDEO_CPIA) += cpia.o @@ -84,8 +83,6 @@ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ obj-$(CONFIG_VIDEO_MXB) += mxb.o obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o -obj-$(CONFIG_VIDEO_DPC) += dpc7146.o -obj-$(CONFIG_TUNER_3036) += tuner-3036.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o @@ -139,6 +136,7 @@ obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o obj-$(CONFIG_SOC_CAMERA) += soc_camera.o obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o +obj-$(CONFIG_SOC_CAMERA_MT9M111) += mt9m111.o obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o diff --git a/linux/drivers/media/video/arv.c b/linux/drivers/media/video/arv.c index 8d8d339b5..9e96e7773 100644 --- a/linux/drivers/media/video/arv.c +++ b/linux/drivers/media/video/arv.c @@ -30,6 +30,7 @@ #include "compat.h" #include <linux/videodev.h> #include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> #include <linux/mutex.h> #include <asm/uaccess.h> @@ -38,7 +39,7 @@ #include <asm/dma.h> #include <asm/byteorder.h> -#if 0 /* keep */; +#if 0 /* keep */ #define DEBUG(n, args...) printk(args) #define CHECK_LOST 1 #else @@ -578,11 +579,11 @@ static void ar_interrupt(int irq, void *dev) * we have to start capture. */ disable_dma(); -#if 0 /* keep */; +#if 0 /* keep */ ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); /* needless? */ #endif memcpy(ar->frame[0], ar->line_buff, ar->line_bytes); -#if 0 /* keep */; +#if 0 /* keep */ ar_outl(0xa1861300, M32R_DMA0CR0_PORTL); #endif enable_dma(); @@ -608,7 +609,7 @@ static void ar_interrupt(int irq, void *dev) ar_outl(arvcr1, ARVCR1); /* disable */ wake_up_interruptible(&ar->wait); } else { -#if 0 /* keep */; +#if 0 /* keep */ ar_outl(ar->line_buff, M32R_DMA0CDA_PORTL); ar_outl(0xa1861300, M32R_DMA0CR0_PORTL); #endif @@ -692,7 +693,7 @@ static int ar_initialize(struct video_device *dev) printk("."); iic(2,0x78,0x8e,0x0c,0x00); iic(2,0x78,0x8f,0x00,0x00); -#if 0 /* keep */; +#if 0 /* keep */ iic(2,0x78,0x90,0x00,0x00); /* AWB on=1 off=0 */ #endif iic(2,0x78,0x93,0x01,0x00); @@ -711,7 +712,7 @@ static int ar_initialize(struct video_device *dev) iic(2,0x78,0x9e,0x2e,0x00); iic(2,0x78,0xb8,0x78,0x00); iic(2,0x78,0xba,0x05,0x00); -#if 0 /* keep */; +#if 0 /* keep */ iic(2,0x78,0x83,0x8c,0x00); /* brightness */ #endif printk("."); @@ -759,9 +760,7 @@ static const struct file_operations ar_fops = { }; static struct video_device ar_template = { - .owner = THIS_MODULE, .name = "Colour AR VGA", - .type = VID_TYPE_CAPTURE, .fops = &ar_fops, .release = ar_release, .minor = -1, diff --git a/linux/drivers/media/video/au0828/Kconfig b/linux/drivers/media/video/au0828/Kconfig index 52b249158..018f72b8e 100644 --- a/linux/drivers/media/video/au0828/Kconfig +++ b/linux/drivers/media/video/au0828/Kconfig @@ -6,6 +6,8 @@ config VIDEO_AU0828 select VIDEO_TVEEPROM select DVB_AU8522 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_MXL5007T if !DVB_FE_CUSTOMIZE + select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE ---help--- This is a video4linux driver for Auvitek's USB device. diff --git a/linux/drivers/media/video/au0828/au0828-cards.c b/linux/drivers/media/video/au0828/au0828-cards.c index 898e12395..14b9fc9bb 100644 --- a/linux/drivers/media/video/au0828/au0828-cards.c +++ b/linux/drivers/media/video/au0828/au0828-cards.c @@ -32,9 +32,15 @@ struct au0828_board au0828_boards[] = { [AU0828_BOARD_HAUPPAUGE_HVR950Q] = { .name = "Hauppauge HVR950Q", }, + [AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL] = { + .name = "Hauppauge HVR950Q rev xxF8", + }, [AU0828_BOARD_DVICO_FUSIONHDTV7] = { .name = "DViCO FusionHDTV USB", }, + [AU0828_BOARD_HAUPPAUGE_WOODBURY] = { + .name = "Hauppauge Woodbury", + }, }; /* Tuner callback function for au0828 boards. Currently only needed @@ -49,6 +55,7 @@ int au0828_tuner_callback(void *priv, int command, int arg) switch (dev->board) { case AU0828_BOARD_HAUPPAUGE_HVR850: case AU0828_BOARD_HAUPPAUGE_HVR950Q: + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: case AU0828_BOARD_DVICO_FUSIONHDTV7: if (command == 0) { /* Tuner Reset Command from xc5000 */ @@ -110,6 +117,8 @@ void au0828_card_setup(struct au0828_dev *dev) switch (dev->board) { case AU0828_BOARD_HAUPPAUGE_HVR850: case AU0828_BOARD_HAUPPAUGE_HVR950Q: + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: + case AU0828_BOARD_HAUPPAUGE_WOODBURY: if (dev->i2c_rc == 0) hauppauge_eeprom(dev, eeprom+0xa0); break; @@ -128,6 +137,8 @@ void au0828_gpio_setup(struct au0828_dev *dev) switch (dev->board) { case AU0828_BOARD_HAUPPAUGE_HVR850: case AU0828_BOARD_HAUPPAUGE_HVR950Q: + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: + case AU0828_BOARD_HAUPPAUGE_WOODBURY: /* GPIO's * 4 - CS5340 * 5 - AU8522 Demodulator @@ -193,6 +204,14 @@ struct usb_device_id au0828_usb_id_table [] = { .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, { USB_DEVICE(0x0fd9, 0x0008), .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q }, + { USB_DEVICE(0x2040, 0x7201), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, + { USB_DEVICE(0x2040, 0x7211), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, + { USB_DEVICE(0x2040, 0x7281), + .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL }, + { USB_DEVICE(0x2040, 0x8200), + .driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY }, { }, }; diff --git a/linux/drivers/media/video/au0828/au0828-cards.h b/linux/drivers/media/video/au0828/au0828-cards.h index e26f54a96..102ed03dc 100644 --- a/linux/drivers/media/video/au0828/au0828-cards.h +++ b/linux/drivers/media/video/au0828/au0828-cards.h @@ -23,3 +23,5 @@ #define AU0828_BOARD_HAUPPAUGE_HVR950Q 1 #define AU0828_BOARD_HAUPPAUGE_HVR850 2 #define AU0828_BOARD_DVICO_FUSIONHDTV7 3 +#define AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL 4 +#define AU0828_BOARD_HAUPPAUGE_WOODBURY 5 diff --git a/linux/drivers/media/video/au0828/au0828-dvb.c b/linux/drivers/media/video/au0828/au0828-dvb.c index 0a835354f..1fa77ba11 100644 --- a/linux/drivers/media/video/au0828/au0828-dvb.c +++ b/linux/drivers/media/video/au0828/au0828-dvb.c @@ -29,6 +29,8 @@ #include "au0828.h" #include "au8522.h" #include "xc5000.h" +#include "mxl5007t.h" +#include "tda18271.h" DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -38,6 +40,15 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static struct au8522_config hauppauge_hvr950q_config = { .demod_address = 0x8e >> 1, .status_mode = AU8522_DEMODLOCKING, + .qam_if = AU8522_IF_6MHZ, + .vsb_if = AU8522_IF_6MHZ, +}; + +static struct au8522_config hauppauge_woodbury_config = { + .demod_address = 0x8e >> 1, + .status_mode = AU8522_DEMODLOCKING, + .qam_if = AU8522_IF_4MHZ, + .vsb_if = AU8522_IF_3_25MHZ, }; static struct xc5000_config hauppauge_hvr950q_tunerconfig = { @@ -46,6 +57,15 @@ static struct xc5000_config hauppauge_hvr950q_tunerconfig = { .tuner_callback = au0828_tuner_callback }; +static struct mxl5007t_config mxl5007t_hvr950q_config = { + .xtal_freq_hz = MxL_XTAL_24_MHZ, + .if_freq_hz = MxL_IF_6_MHZ, +}; + +static struct tda18271_config hauppauge_woodbury_tunerconfig = { + .gate = TDA18271_GATE_DIGITAL, +}; + /*-------------------------------------------------------------------*/ #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) static void urb_completion(struct urb *purb, struct pt_regs *regs) @@ -347,6 +367,24 @@ int au0828_dvb_register(struct au0828_dev *dev) &dev->i2c_adap, &hauppauge_hvr950q_tunerconfig, dev); break; + case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL: + dvb->frontend = dvb_attach(au8522_attach, + &hauppauge_hvr950q_config, + &dev->i2c_adap); + if (dvb->frontend != NULL) + dvb_attach(mxl5007t_attach, dvb->frontend, + &dev->i2c_adap, 0x60, + &mxl5007t_hvr950q_config); + break; + case AU0828_BOARD_HAUPPAUGE_WOODBURY: + dvb->frontend = dvb_attach(au8522_attach, + &hauppauge_woodbury_config, + &dev->i2c_adap); + if (dvb->frontend != NULL) + dvb_attach(tda18271_attach, dvb->frontend, + 0x60, &dev->i2c_adap, + &hauppauge_woodbury_tunerconfig); + break; default: printk(KERN_WARNING "The frontend of your DVB/ATSC card " "isn't supported yet\n"); diff --git a/linux/drivers/media/video/bt8xx/Kconfig b/linux/drivers/media/video/bt8xx/Kconfig index 24a34fc1f..ce71e8e7b 100644 --- a/linux/drivers/media/video/bt8xx/Kconfig +++ b/linux/drivers/media/video/bt8xx/Kconfig @@ -1,9 +1,7 @@ config VIDEO_BT848 tristate "BT848 Video For Linux" depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT - depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT - select FW_LOADER select VIDEO_BTCX select VIDEOBUF_DMA_SG select VIDEO_IR diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c index ff9d09f09..bf3339436 100644 --- a/linux/drivers/media/video/bt8xx/bttv-cards.c +++ b/linux/drivers/media/video/bt8xx/bttv-cards.c @@ -309,7 +309,7 @@ static struct CARD { { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "}, { 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" }, { 0x763c008a, BTTV_BOARD_GEOVISION_GV600, "GeoVision GV-600" }, - + { 0x18011000, BTTV_BOARD_ENLTV_FM_2, "Encore ENL TV-FM-2" }, { 0, -1, NULL } }; @@ -3069,6 +3069,31 @@ struct tvcard bttv_tvcards[] = { .has_radio = 1, .has_remote = 1, }, + [BTTV_BOARD_ENLTV_FM_2] = { + /* Encore TV Tuner Pro ENL TV-FM-2 + Mauro Carvalho Chehab <mchehab@infradead.org */ + .name = "Encore ENL TV-FM-2", + .video_inputs = 3, + .audio_inputs = 1, + .tuner = 0, + .svhs = 2, + /* bit 6 -> IR disabled + bit 18/17 = 00 -> mute + 01 -> enable external audio input + 10 -> internal audio input (mono?) + 11 -> internal audio input + */ + .gpiomask = 0x060040, + .muxsel = { 2, 3, 3 }, + .gpiomux = { 0x60000, 0x60000, 0x20000, 0x20000 }, + .gpiomute = 0, + .tuner_type = TUNER_TCL_MF02GIP_5N, + .tuner_addr = ADDR_UNSET, + .radio_addr = ADDR_UNSET, + .pll = PLL_28, + .has_radio = 1, + .has_remote = 1, + } }; static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards); diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c index 17fa68233..012eeba5e 100644 --- a/linux/drivers/media/video/bt8xx/bttv-driver.c +++ b/linux/drivers/media/video/bt8xx/bttv-driver.c @@ -3248,6 +3248,7 @@ static int bttv_open(struct inode *inode, struct file *file) dprintk(KERN_DEBUG "bttv: open minor=%d\n",minor); + lock_kernel(); for (i = 0; i < bttv_num; i++) { if (bttvs[i].video_dev && bttvs[i].video_dev->minor == minor) { @@ -3262,16 +3263,20 @@ static int bttv_open(struct inode *inode, struct file *file) break; } } - if (NULL == btv) + if (NULL == btv) { + unlock_kernel(); return -ENODEV; + } dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n", btv->c.nr,v4l2_type_names[type]); /* allocate per filehandle data */ fh = kmalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) + if (NULL == fh) { + unlock_kernel(); return -ENOMEM; + } file->private_data = fh; *fh = btv->init; fh->type = type; @@ -3291,6 +3296,7 @@ static int bttv_open(struct inode *inode, struct file *file) sizeof(struct bttv_buffer), fh); set_tvnorm(btv,btv->tvnorm); + set_input(btv, btv->input, btv->tvnorm); btv->users++; @@ -3311,6 +3317,7 @@ static int bttv_open(struct inode *inode, struct file *file) bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm); bttv_field_count(btv); + unlock_kernel(); return 0; } @@ -3351,6 +3358,10 @@ static int bttv_release(struct inode *inode, struct file *file) btv->users--; bttv_field_count(btv); + + if (!btv->users) + audio_mute(btv, 1); + return 0; } @@ -3378,10 +3389,7 @@ static const struct file_operations bttv_fops = .poll = bttv_poll, }; -static struct video_device bttv_video_template = -{ - .fops = &bttv_fops, - .minor = -1, +static const struct v4l2_ioctl_ops bttv_ioctl_ops = { .vidioc_querycap = bttv_querycap, .vidioc_enum_fmt_vid_cap = bttv_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = bttv_g_fmt_vid_cap, @@ -3432,8 +3440,14 @@ static struct video_device bttv_video_template = .vidioc_g_register = bttv_g_register, .vidioc_s_register = bttv_s_register, #endif - .tvnorms = BTTV_NORMS, - .current_norm = V4L2_STD_PAL, +}; + +static struct video_device bttv_video_template = { + .fops = &bttv_fops, + .minor = -1, + .ioctl_ops = &bttv_ioctl_ops, + .tvnorms = BTTV_NORMS, + .current_norm = V4L2_STD_PAL, }; /* ----------------------------------------------------------------------- */ @@ -3448,21 +3462,26 @@ static int radio_open(struct inode *inode, struct file *file) dprintk("bttv: open minor=%d\n",minor); + lock_kernel(); for (i = 0; i < bttv_num; i++) { if (bttvs[i].radio_dev->minor == minor) { btv = &bttvs[i]; break; } } - if (NULL == btv) + if (NULL == btv) { + unlock_kernel(); return -ENODEV; + } dprintk("bttv%d: open called (radio)\n",btv->c.nr); /* allocate per filehandle data */ fh = kmalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) + if (NULL == fh) { + unlock_kernel(); return -ENOMEM; + } file->private_data = fh; *fh = btv->init; v4l2_prio_open(&btv->prio, &fh->prio); @@ -3475,6 +3494,7 @@ static int radio_open(struct inode *inode, struct file *file) audio_input(btv,TVAUDIO_INPUT_RADIO); mutex_unlock(&btv->lock); + unlock_kernel(); return 0; } @@ -3656,10 +3676,7 @@ static const struct file_operations radio_fops = .poll = radio_poll, }; -static struct video_device radio_template = -{ - .fops = &radio_fops, - .minor = -1, +static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = radio_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, @@ -3676,6 +3693,12 @@ static struct video_device radio_template = .vidioc_s_frequency = bttv_s_frequency, }; +static struct video_device radio_template = { + .fops = &radio_fops, + .minor = -1, + .ioctl_ops = &radio_ioctl_ops, +}; + /* ----------------------------------------------------------------------- */ /* some debug code */ @@ -4200,8 +4223,7 @@ static irqreturn_t bttv_irq(int irq, void *dev_id) static struct video_device *vdev_init(struct bttv *btv, const struct video_device *template, - const char *type_name, - const int type) + const char *type_name) { struct video_device *vfd; @@ -4212,7 +4234,6 @@ static struct video_device *vdev_init(struct bttv *btv, vfd->minor = -1; vfd->parent = &btv->c.pci->dev; vfd->release = video_device_release; - vfd->type = type; vfd->debug = bttv_debug; snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)", btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "", @@ -4248,20 +4269,11 @@ static void bttv_unregister_video(struct bttv *btv) /* register video4linux devices */ static int __devinit bttv_register_video(struct bttv *btv) { - int video_type = VID_TYPE_CAPTURE | - VID_TYPE_TUNER | - VID_TYPE_CLIPPING| - VID_TYPE_SCALES; - - if (no_overlay <= 0) { - bttv_video_template.type |= VID_TYPE_OVERLAY; - } else { + if (no_overlay > 0) printk("bttv: Overlay support disabled.\n"); - } /* video */ - btv->video_dev = vdev_init(btv, &bttv_video_template, - "video", video_type); + btv->video_dev = vdev_init(btv, &bttv_video_template, "video"); if (NULL == btv->video_dev) goto err; @@ -4277,8 +4289,7 @@ static int __devinit bttv_register_video(struct bttv *btv) } /* vbi */ - btv->vbi_dev = vdev_init(btv, &bttv_video_template, - "vbi", VID_TYPE_TUNER | VID_TYPE_TELETEXT); + btv->vbi_dev = vdev_init(btv, &bttv_video_template, "vbi"); if (NULL == btv->vbi_dev) goto err; @@ -4290,8 +4301,7 @@ static int __devinit bttv_register_video(struct bttv *btv) if (!btv->has_radio) return 0; /* radio */ - btv->radio_dev = vdev_init(btv, &radio_template, - "radio", VID_TYPE_TUNER); + btv->radio_dev = vdev_init(btv, &radio_template, "radio"); if (NULL == btv->radio_dev) goto err; if (video_register_device(btv->radio_dev, VFL_TYPE_RADIO,radio_nr)<0) diff --git a/linux/drivers/media/video/bt8xx/bttv-input.c b/linux/drivers/media/video/bt8xx/bttv-input.c index 09dc5ac77..a6b403a01 100644 --- a/linux/drivers/media/video/bt8xx/bttv-input.c +++ b/linux/drivers/media/video/bt8xx/bttv-input.c @@ -28,8 +28,8 @@ #include "bttvp.h" -static int debug; -module_param(debug, int, 0644); /* debug level (0,1,2) */ +static int ir_debug; +module_param(ir_debug, int, 0644); static int repeat_delay = 500; module_param(repeat_delay, int, 0644); static int repeat_period = 33; @@ -40,6 +40,12 @@ module_param(ir_rc5_remote_gap, int, 0644); static int ir_rc5_key_timeout = 200; module_param(ir_rc5_key_timeout, int, 0644); +#undef dprintk +#define dprintk(arg...) do { \ + if (ir_debug >= 1) \ + printk(arg); \ +} while (0) + #define DEVNAME "bttv-input" /* ---------------------------------------------------------------------- */ @@ -79,6 +85,45 @@ static void ir_handle_key(struct bttv *btv) } +static void ir_enltv_handle_key(struct bttv *btv) +{ + struct card_ir *ir = btv->remote; + u32 gpio, data, keyup; + + /* read gpio value */ + gpio = bttv_gpio_read(&btv->c); + + /* extract data */ + data = ir_extract_bits(gpio, ir->mask_keycode); + + /* Check if it is keyup */ + keyup = (gpio & ir->mask_keyup) ? 1 << 31 : 0; + + if ((ir->last_gpio & 0x7f) != data) { + dprintk(KERN_INFO DEVNAME ": gpio=0x%x code=%d | %s\n", + gpio, data, + (gpio & ir->mask_keyup) ? " up" : "up/down"); + + ir_input_keydown(ir->dev, &ir->ir, data, data); + if (keyup) + ir_input_nokey(ir->dev, &ir->ir); + } else { + if ((ir->last_gpio & 1 << 31) == keyup) + return; + + dprintk(KERN_INFO DEVNAME ":(cnt) gpio=0x%x code=%d | %s\n", + gpio, data, + (gpio & ir->mask_keyup) ? " up" : "down"); + + if (keyup) + ir_input_nokey(ir->dev, &ir->ir); + else + ir_input_keydown(ir->dev, &ir->ir, data, data); + } + + ir->last_gpio = data | keyup; +} + void bttv_input_irq(struct bttv *btv) { struct card_ir *ir = btv->remote; @@ -92,7 +137,10 @@ static void bttv_input_timer(unsigned long data) struct bttv *btv = (struct bttv*)data; struct card_ir *ir = btv->remote; - ir_handle_key(btv); + if (btv->c.type == BTTV_BOARD_ENLTV_FM_2) + ir_enltv_handle_key(btv); + else + ir_handle_key(btv); mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling)); } @@ -284,6 +332,14 @@ int bttv_input_init(struct bttv *btv) ir->mask_keyup = 0x006000; ir->polling = 50; /* ms */ break; + case BTTV_BOARD_ENLTV_FM_2: + ir_codes = ir_codes_encore_enltv2; + ir->mask_keycode = 0x00fd00; + ir->mask_keyup = 0x000080; + ir->polling = 1; /* ms */ + ir->last_gpio = ir_extract_bits(bttv_gpio_read(&btv->c), + ir->mask_keycode); + break; } if (NULL == ir_codes) { dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type); diff --git a/linux/drivers/media/video/bt8xx/bttv.h b/linux/drivers/media/video/bt8xx/bttv.h index 3441c0226..0f2a33eb3 100644 --- a/linux/drivers/media/video/bt8xx/bttv.h +++ b/linux/drivers/media/video/bt8xx/bttv.h @@ -177,7 +177,7 @@ #define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95 #define BTTV_BOARD_GEOVISION_GV600 0x96 #define BTTV_BOARD_KOZUMI_KTV_01C 0x97 - +#define BTTV_BOARD_ENLTV_FM_2 0x98 /* more card-specific defines */ #define PT2254_L_CHANNEL 0x10 diff --git a/linux/drivers/media/video/bw-qcam.c b/linux/drivers/media/video/bw-qcam.c index cc247d6bb..df2b25b69 100644 --- a/linux/drivers/media/video/bw-qcam.c +++ b/linux/drivers/media/video/bw-qcam.c @@ -908,9 +908,7 @@ static const struct file_operations qcam_fops = { }; static struct video_device qcam_template= { - .owner = THIS_MODULE, .name = "Connectix Quickcam", - .type = VID_TYPE_CAPTURE, .fops = &qcam_fops, }; diff --git a/linux/drivers/media/video/c-qcam.c b/linux/drivers/media/video/c-qcam.c index 3824c8601..fe8937ed1 100644 --- a/linux/drivers/media/video/c-qcam.c +++ b/linux/drivers/media/video/c-qcam.c @@ -703,9 +703,7 @@ static const struct file_operations qcam_fops = { static struct video_device qcam_template= { - .owner = THIS_MODULE, .name = "Colour QuickCam", - .type = VID_TYPE_CAPTURE, .fops = &qcam_fops, }; diff --git a/linux/drivers/media/video/cafe_ccic.c b/linux/drivers/media/video/cafe_ccic.c index 075d57031..4c0d44c5d 100644 --- a/linux/drivers/media/video/cafe_ccic.c +++ b/linux/drivers/media/video/cafe_ccic.c @@ -1482,9 +1482,12 @@ static int cafe_v4l_open(struct inode *inode, struct file *filp) { struct cafe_camera *cam; + lock_kernel(); cam = cafe_find_dev(iminor(inode)); - if (cam == NULL) + if (cam == NULL) { + unlock_kernel(); return -ENODEV; + } filp->private_data = cam; mutex_lock(&cam->s_mutex); @@ -1496,6 +1499,7 @@ static int cafe_v4l_open(struct inode *inode, struct file *filp) } (cam->users)++; mutex_unlock(&cam->s_mutex); + unlock_kernel(); return 0; } @@ -1776,17 +1780,7 @@ static const struct file_operations cafe_v4l_fops = { .llseek = no_llseek, }; -static struct video_device cafe_v4l_template = { - .name = "cafe", - .type = VFL_TYPE_GRABBER, - .type2 = VID_TYPE_CAPTURE, - .minor = -1, /* Get one dynamically */ - .tvnorms = V4L2_STD_NTSC_M, - .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ - - .fops = &cafe_v4l_fops, - .release = cafe_v4l_dev_release, - +static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = { .vidioc_querycap = cafe_vidioc_querycap, .vidioc_enum_fmt_vid_cap = cafe_vidioc_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap = cafe_vidioc_try_fmt_vid_cap, @@ -1809,6 +1803,17 @@ static struct video_device cafe_v4l_template = { .vidioc_s_parm = cafe_vidioc_s_parm, }; +static struct video_device cafe_v4l_template = { + .name = "cafe", + .minor = -1, /* Get one dynamically */ + .tvnorms = V4L2_STD_NTSC_M, + .current_norm = V4L2_STD_NTSC_M, /* make mplayer happy */ + + .fops = &cafe_v4l_fops, + .ioctl_ops = &cafe_v4l_ioctl_ops, + .release = cafe_v4l_dev_release, +}; + diff --git a/linux/drivers/media/video/cpia.c b/linux/drivers/media/video/cpia.c index d5941cc15..21c1f4dbb 100644 --- a/linux/drivers/media/video/cpia.c +++ b/linux/drivers/media/video/cpia.c @@ -3799,9 +3799,7 @@ static const struct file_operations cpia_fops = { }; static struct video_device cpia_template = { - .owner = THIS_MODULE, .name = "CPiA Camera", - .type = VID_TYPE_CAPTURE, .fops = &cpia_fops, }; diff --git a/linux/drivers/media/video/cpia2/cpia2_core.c b/linux/drivers/media/video/cpia2/cpia2_core.c index eab48dfd0..ce43a054a 100644 --- a/linux/drivers/media/video/cpia2/cpia2_core.c +++ b/linux/drivers/media/video/cpia2/cpia2_core.c @@ -32,6 +32,7 @@ #include "cpia2.h" #include <linux/slab.h> +#include <linux/mm.h> #include <linux/vmalloc.h> #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) #include <linux/firmware.h> diff --git a/linux/drivers/media/video/cpia2/cpia2_v4l.c b/linux/drivers/media/video/cpia2/cpia2_v4l.c index 8817c3841..515c8b57a 100644 --- a/linux/drivers/media/video/cpia2/cpia2_v4l.c +++ b/linux/drivers/media/video/cpia2/cpia2_v4l.c @@ -1936,11 +1936,7 @@ static const struct file_operations fops_template = { 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, .minor= -1, .fops= &fops_template, .release= video_device_release, diff --git a/linux/drivers/media/video/cs53l32a.c b/linux/drivers/media/video/cs53l32a.c index bef0950e5..f5ea3f4a9 100644 --- a/linux/drivers/media/video/cs53l32a.c +++ b/linux/drivers/media/video/cs53l32a.c @@ -26,7 +26,7 @@ #include <asm/uaccess.h> #include <linux/i2c.h> #include <linux/i2c-id.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-i2c-drv-legacy.h> diff --git a/linux/drivers/media/video/cx18/Kconfig b/linux/drivers/media/video/cx18/Kconfig index 9aefdc5ea..ef48565de 100644 --- a/linux/drivers/media/video/cx18/Kconfig +++ b/linux/drivers/media/video/cx18/Kconfig @@ -2,9 +2,7 @@ config VIDEO_CX18 tristate "Conexant cx23418 MPEG encoder support" depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL depends on INPUT # due to VIDEO_IR - depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT - select FW_LOADER select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM diff --git a/linux/drivers/media/video/cx18/cx18-av-audio.c b/linux/drivers/media/video/cx18/cx18-av-audio.c index c40a286de..0b5583788 100644 --- a/linux/drivers/media/video/cx18/cx18-av-audio.c +++ b/linux/drivers/media/video/cx18/cx18-av-audio.c @@ -30,7 +30,6 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) if (freq != 32000 && freq != 44100 && freq != 48000) return -EINVAL; - /* common for all inputs and rates */ /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */ cx18_av_write(cx, 0x127, 0x50); @@ -38,15 +37,30 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) switch (freq) { case 32000: /* VID_PLL and AUX_PLL */ - cx18_av_write4(cx, 0x108, 0x1006040f); + cx18_av_write4(cx, 0x108, 0x1408040f); /* AUX_PLL_FRAC */ - cx18_av_write4(cx, 0x110, 0x01bb39ee); + /* 0x8.9504318a * 28,636,363.636 / 0x14 = 32000 * 384 */ + cx18_av_write4(cx, 0x110, 0x012a0863); - /* src3/4/6_ctl = 0x0801f77f */ + /* src3/4/6_ctl */ + /* 0x1.f77f = (4 * 15734.26) / 32000 */ cx18_av_write4(cx, 0x900, 0x0801f77f); cx18_av_write4(cx, 0x904, 0x0801f77f); cx18_av_write4(cx, 0x90c, 0x0801f77f); + + /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ + cx18_av_write(cx, 0x127, 0x54); + + /* AUD_COUNT = 0x2fff = 8 samples * 4 * 384 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11202fff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 = + * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa10d2ef8); break; case 44100: @@ -54,12 +68,24 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x1009040f); /* AUX_PLL_FRAC */ - cx18_av_write4(cx, 0x110, 0x00ec6bd6); + /* 0x9.7635e7 * 28,636,363.63 / 0x10 = 44100 * 384 */ + cx18_av_write4(cx, 0x110, 0x00ec6bce); - /* src3/4/6_ctl = 0x08016d59 */ + /* src3/4/6_ctl */ + /* 0x1.6d59 = (4 * 15734.26) / 44100 */ cx18_av_write4(cx, 0x900, 0x08016d59); cx18_av_write4(cx, 0x904, 0x08016d59); cx18_av_write4(cx, 0x90c, 0x08016d59); + + /* AUD_COUNT = 0x92ff = 49 samples * 2 * 384 - 1 */ + cx18_av_write4(cx, 0x12c, 0x112092ff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 = + * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa11d4bf8); break; case 48000: @@ -67,12 +93,24 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x100a040f); /* AUX_PLL_FRAC */ - cx18_av_write4(cx, 0x110, 0x0098d6e5); + /* 0xa.4c6b6ea * 28,636,363.63 / 0x10 = 48000 * 384 */ + cx18_av_write4(cx, 0x110, 0x0098d6dd); - /* src3/4/6_ctl = 0x08014faa */ + /* src3/4/6_ctl */ + /* 0x1.4faa = (4 * 15734.26) / 48000 */ cx18_av_write4(cx, 0x900, 0x08014faa); cx18_av_write4(cx, 0x904, 0x08014faa); cx18_av_write4(cx, 0x90c, 0x08014faa); + + /* AUD_COUNT = 0x5fff = 4 samples * 16 * 384 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11205fff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x1193f8 = 143999.000 * 8 = + * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa11193f8); break; } } else { @@ -82,18 +120,31 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x1e08040f); /* AUX_PLL_FRAC */ - cx18_av_write4(cx, 0x110, 0x012a0869); + /* 0x8.9504318 * 28,636,363.63 / 0x1e = 32000 * 256 */ + cx18_av_write4(cx, 0x110, 0x012a0863); - /* src1_ctl = 0x08010000 */ + /* src1_ctl */ + /* 0x1.0000 = 32000/32000 */ cx18_av_write4(cx, 0x8f8, 0x08010000); - /* src3/4/6_ctl = 0x08020000 */ + /* src3/4/6_ctl */ + /* 0x2.0000 = 2 * (32000/32000) */ cx18_av_write4(cx, 0x900, 0x08020000); cx18_av_write4(cx, 0x904, 0x08020000); cx18_av_write4(cx, 0x90c, 0x08020000); /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */ cx18_av_write(cx, 0x127, 0x54); + + /* AUD_COUNT = 0x1fff = 8 samples * 4 * 256 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11201fff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x0d2ef8 = 107999.000 * 8 = + * ((8 samples/32,000) * (13,500,000 * 8) * 4 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa10d2ef8); break; case 44100: @@ -101,15 +152,28 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x1809040f); /* AUX_PLL_FRAC */ - cx18_av_write4(cx, 0x110, 0x00ec6bd6); + /* 0x9.7635e74 * 28,636,363.63 / 0x18 = 44100 * 256 */ + cx18_av_write4(cx, 0x110, 0x00ec6bce); - /* src1_ctl = 0x08010000 */ + /* src1_ctl */ + /* 0x1.60cd = 44100/32000 */ cx18_av_write4(cx, 0x8f8, 0x080160cd); - /* src3/4/6_ctl = 0x08020000 */ + /* src3/4/6_ctl */ + /* 0x1.7385 = 2 * (32000/44100) */ cx18_av_write4(cx, 0x900, 0x08017385); cx18_av_write4(cx, 0x904, 0x08017385); cx18_av_write4(cx, 0x90c, 0x08017385); + + /* AUD_COUNT = 0x61ff = 49 samples * 2 * 256 - 1 */ + cx18_av_write4(cx, 0x12c, 0x112061ff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x1d4bf8 = 239999.000 * 8 = + * ((49 samples/44,100) * (13,500,000 * 8) * 2 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa11d4bf8); break; case 48000: @@ -117,15 +181,28 @@ static int set_audclk_freq(struct cx18 *cx, u32 freq) cx18_av_write4(cx, 0x108, 0x180a040f); /* AUX_PLL_FRAC */ - cx18_av_write4(cx, 0x110, 0x0098d6e5); + /* 0xa.4c6b6ea * 28,636,363.63 / 0x18 = 48000 * 256 */ + cx18_av_write4(cx, 0x110, 0x0098d6dd); - /* src1_ctl = 0x08010000 */ + /* src1_ctl */ + /* 0x1.8000 = 48000/32000 */ cx18_av_write4(cx, 0x8f8, 0x08018000); - /* src3/4/6_ctl = 0x08020000 */ + /* src3/4/6_ctl */ + /* 0x1.5555 = 2 * (32000/48000) */ cx18_av_write4(cx, 0x900, 0x08015555); cx18_av_write4(cx, 0x904, 0x08015555); cx18_av_write4(cx, 0x90c, 0x08015555); + + /* AUD_COUNT = 0x3fff = 4 samples * 16 * 256 - 1 */ + cx18_av_write4(cx, 0x12c, 0x11203fff); + + /* + * EN_AV_LOCK = 1 + * VID_COUNT = 0x1193f8 = 143999.000 * 8 = + * ((4 samples/48,000) * (13,500,000 * 8) * 16 - 1) * 8 + */ + cx18_av_write4(cx, 0x128, 0xa11193f8); break; } } diff --git a/linux/drivers/media/video/cx18/cx18-ioctl.c b/linux/drivers/media/video/cx18/cx18-ioctl.c index 0221a67aa..e6c2bfa5d 100644 --- a/linux/drivers/media/video/cx18/cx18-ioctl.c +++ b/linux/drivers/media/video/cx18/cx18-ioctl.c @@ -892,50 +892,54 @@ int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return res; } -void cx18_set_funcs(struct video_device *vdev) -{ - vdev->vidioc_querycap = cx18_querycap; - vdev->vidioc_g_priority = cx18_g_priority; - vdev->vidioc_s_priority = cx18_s_priority; - vdev->vidioc_s_audio = cx18_s_audio; - vdev->vidioc_g_audio = cx18_g_audio; - vdev->vidioc_enumaudio = cx18_enumaudio; - vdev->vidioc_enum_input = cx18_enum_input; - vdev->vidioc_cropcap = cx18_cropcap; - vdev->vidioc_s_crop = cx18_s_crop; - vdev->vidioc_g_crop = cx18_g_crop; - vdev->vidioc_g_input = cx18_g_input; - vdev->vidioc_s_input = cx18_s_input; - vdev->vidioc_g_frequency = cx18_g_frequency; - vdev->vidioc_s_frequency = cx18_s_frequency; - vdev->vidioc_s_tuner = cx18_s_tuner; - vdev->vidioc_g_tuner = cx18_g_tuner; - vdev->vidioc_g_enc_index = cx18_g_enc_index; - vdev->vidioc_g_std = cx18_g_std; - vdev->vidioc_s_std = cx18_s_std; - vdev->vidioc_log_status = cx18_log_status; - vdev->vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap; - vdev->vidioc_encoder_cmd = cx18_encoder_cmd; - vdev->vidioc_try_encoder_cmd = cx18_try_encoder_cmd; - vdev->vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap; - vdev->vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap; - vdev->vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap; - vdev->vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap; - vdev->vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap; - vdev->vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap; - vdev->vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap; - vdev->vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap; - vdev->vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap; - vdev->vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap; - vdev->vidioc_g_chip_ident = cx18_g_chip_ident; +static const struct v4l2_ioctl_ops cx18_ioctl_ops = { + .vidioc_querycap = cx18_querycap, + .vidioc_g_priority = cx18_g_priority, + .vidioc_s_priority = cx18_s_priority, + .vidioc_s_audio = cx18_s_audio, + .vidioc_g_audio = cx18_g_audio, + .vidioc_enumaudio = cx18_enumaudio, + .vidioc_enum_input = cx18_enum_input, + .vidioc_cropcap = cx18_cropcap, + .vidioc_s_crop = cx18_s_crop, + .vidioc_g_crop = cx18_g_crop, + .vidioc_g_input = cx18_g_input, + .vidioc_s_input = cx18_s_input, + .vidioc_g_frequency = cx18_g_frequency, + .vidioc_s_frequency = cx18_s_frequency, + .vidioc_s_tuner = cx18_s_tuner, + .vidioc_g_tuner = cx18_g_tuner, + .vidioc_g_enc_index = cx18_g_enc_index, + .vidioc_g_std = cx18_g_std, + .vidioc_s_std = cx18_s_std, + .vidioc_log_status = cx18_log_status, + .vidioc_enum_fmt_vid_cap = cx18_enum_fmt_vid_cap, + .vidioc_encoder_cmd = cx18_encoder_cmd, + .vidioc_try_encoder_cmd = cx18_try_encoder_cmd, + .vidioc_g_fmt_vid_cap = cx18_g_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = cx18_g_fmt_vbi_cap, + .vidioc_g_fmt_sliced_vbi_cap = cx18_g_fmt_sliced_vbi_cap, + .vidioc_s_fmt_vid_cap = cx18_s_fmt_vid_cap, + .vidioc_s_fmt_vbi_cap = cx18_s_fmt_vbi_cap, + .vidioc_s_fmt_sliced_vbi_cap = cx18_s_fmt_sliced_vbi_cap, + .vidioc_try_fmt_vid_cap = cx18_try_fmt_vid_cap, + .vidioc_try_fmt_vbi_cap = cx18_try_fmt_vbi_cap, + .vidioc_try_fmt_sliced_vbi_cap = cx18_try_fmt_sliced_vbi_cap, + .vidioc_g_sliced_vbi_cap = cx18_g_sliced_vbi_cap, + .vidioc_g_chip_ident = cx18_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG - vdev->vidioc_g_register = cx18_g_register; - vdev->vidioc_s_register = cx18_s_register; + .vidioc_g_register = cx18_g_register, + .vidioc_s_register = cx18_s_register, #endif - vdev->vidioc_default = cx18_default; - vdev->vidioc_queryctrl = cx18_queryctrl; - vdev->vidioc_querymenu = cx18_querymenu; - vdev->vidioc_g_ext_ctrls = cx18_g_ext_ctrls; - vdev->vidioc_s_ext_ctrls = cx18_s_ext_ctrls; - vdev->vidioc_try_ext_ctrls = cx18_try_ext_ctrls; + .vidioc_default = cx18_default, + .vidioc_queryctrl = cx18_queryctrl, + .vidioc_querymenu = cx18_querymenu, + .vidioc_g_ext_ctrls = cx18_g_ext_ctrls, + .vidioc_s_ext_ctrls = cx18_s_ext_ctrls, + .vidioc_try_ext_ctrls = cx18_try_ext_ctrls, +}; + +void cx18_set_funcs(struct video_device *vdev) +{ + vdev->ioctl_ops = &cx18_ioctl_ops; } diff --git a/linux/drivers/media/video/cx18/cx18-irq.c b/linux/drivers/media/video/cx18/cx18-irq.c index 654664783..b9cf609ee 100644 --- a/linux/drivers/media/video/cx18/cx18-irq.c +++ b/linux/drivers/media/video/cx18/cx18-irq.c @@ -61,7 +61,7 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb) CX18_WARN("Ack struct = %d for %s\n", mb->args[2], s->name); id = read_enc(off); - buf = cx18_queue_find_buf(s, id, read_enc(off + 4)); + buf = cx18_queue_get_buf_irq(s, id, read_enc(off + 4)); CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id); if (buf) { cx18_buf_sync_for_cpu(s, buf); diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index 6990b77c6..8a4dd821f 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -78,12 +78,13 @@ struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q) return buf; } -struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, +struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, u32 bytesused) { struct cx18 *cx = s->cx; struct list_head *p; + spin_lock(&s->qlock); list_for_each(p, &s->q_free.list) { struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list); @@ -92,17 +93,19 @@ struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, continue; buf->bytesused = bytesused; /* the transport buffers are handled differently, - so there is no need to move them to the full queue */ - if (s->type == CX18_ENC_STREAM_TYPE_TS) - return buf; - s->q_free.buffers--; - s->q_free.length -= s->buf_size; - s->q_full.buffers++; - s->q_full.length += s->buf_size; - s->q_full.bytesused += buf->bytesused; - list_move_tail(&buf->list, &s->q_full.list); + they are not moved to the full queue */ + if (s->type != CX18_ENC_STREAM_TYPE_TS) { + s->q_free.buffers--; + s->q_free.length -= s->buf_size; + s->q_full.buffers++; + s->q_full.length += s->buf_size; + s->q_full.bytesused += buf->bytesused; + list_move_tail(&buf->list, &s->q_full.list); + } + spin_unlock(&s->qlock); return buf; } + spin_unlock(&s->qlock); CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name); return NULL; } diff --git a/linux/drivers/media/video/cx18/cx18-queue.h b/linux/drivers/media/video/cx18/cx18-queue.h index 91423b986..7f93bb13c 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.h +++ b/linux/drivers/media/video/cx18/cx18-queue.h @@ -46,7 +46,7 @@ void cx18_queue_init(struct cx18_queue *q); void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf, struct cx18_queue *q); struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q); -struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id, +struct cx18_buffer *cx18_queue_get_buf_irq(struct cx18_stream *s, u32 id, u32 bytesused); void cx18_flush_queues(struct cx18_stream *s); diff --git a/linux/drivers/media/video/cx18/cx18-streams.c b/linux/drivers/media/video/cx18/cx18-streams.c index 3eedae726..911a97ce3 100644 --- a/linux/drivers/media/video/cx18/cx18-streams.c +++ b/linux/drivers/media/video/cx18/cx18-streams.c @@ -187,9 +187,6 @@ static int cx18_prep_dev(struct cx18 *cx, int type) return -ENOMEM; } - s->v4l2dev->type = - VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | - VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18-%d", cx->num); diff --git a/linux/drivers/media/video/cx2341x.c b/linux/drivers/media/video/cx2341x.c index 835062f5b..f31f11e3f 100644 --- a/linux/drivers/media/video/cx2341x.c +++ b/linux/drivers/media/video/cx2341x.c @@ -509,7 +509,10 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params, /* this setting is read-only for the cx2341x since the V4L2_CID_MPEG_STREAM_TYPE really determines the MPEG-1/2 setting */ - err = v4l2_ctrl_query_fill_std(qctrl); + err = v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_VIDEO_ENCODING_MPEG_1, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1, + V4L2_MPEG_VIDEO_ENCODING_MPEG_2); if (err == 0) qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; return err; diff --git a/linux/drivers/media/video/cx23885/Kconfig b/linux/drivers/media/video/cx23885/Kconfig index 5cfb46bbd..e60bd31b5 100644 --- a/linux/drivers/media/video/cx23885/Kconfig +++ b/linux/drivers/media/video/cx23885/Kconfig @@ -1,9 +1,7 @@ config VIDEO_CX23885 tristate "Conexant cx23885 (2388x successor) support" depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT - depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT - select FW_LOADER select VIDEO_BTCX select VIDEO_TUNER select VIDEO_TVEEPROM diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c index 3c3563f73..106b594ed 100644 --- a/linux/drivers/media/video/cx23885/cx23885-417.c +++ b/linux/drivers/media/video/cx23885/cx23885-417.c @@ -1591,6 +1591,7 @@ static int mpeg_open(struct inode *inode, struct file *file) dprintk(2, "%s()\n", __func__); + lock_kernel(); list_for_each(list, &cx23885_devlist) { h = list_entry(list, struct cx23885_dev, devlist); if (h->v4l_device->minor == minor) { @@ -1599,13 +1600,17 @@ static int mpeg_open(struct inode *inode, struct file *file) } } - if (dev == NULL) + if (dev == NULL) { + unlock_kernel(); return -ENODEV; + } /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) + if (NULL == fh) { + unlock_kernel(); return -ENOMEM; + } file->private_data = fh; fh->dev = dev; @@ -1616,6 +1621,7 @@ static int mpeg_open(struct inode *inode, struct file *file) V4L2_FIELD_INTERLACED, sizeof(struct cx23885_buffer), fh); + unlock_kernel(); return 0; } @@ -1708,14 +1714,7 @@ static struct file_operations mpeg_fops = { .llseek = no_llseek, }; -static struct video_device cx23885_mpeg_template = { - .name = "cx23885", - .type = VID_TYPE_CAPTURE | - VID_TYPE_TUNER | - VID_TYPE_SCALES | - VID_TYPE_MPEG_ENCODER, - .fops = &mpeg_fops, - .minor = -1, +static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_s_std = vidioc_s_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, @@ -1744,6 +1743,13 @@ static struct video_device cx23885_mpeg_template = { .vidioc_queryctrl = vidioc_queryctrl, }; +static struct video_device cx23885_mpeg_template = { + .name = "cx23885", + .fops = &mpeg_fops, + .ioctl_ops = &mpeg_ioctl_ops, + .minor = -1, +}; + void cx23885_417_unregister(struct cx23885_dev *dev) { dprintk(1, "%s()\n", __func__); diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c index 7171e344a..f7cb19256 100644 --- a/linux/drivers/media/video/cx23885/cx23885-cards.c +++ b/linux/drivers/media/video/cx23885/cx23885-cards.c @@ -27,6 +27,7 @@ #include "compat.h" #include "cx23885.h" +#include "tuner-xc2028.h" /* ------------------------------------------------------------------ */ /* board config info */ @@ -146,9 +147,12 @@ struct cx23885_board cx23885_boards[] = { }, [CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP] = { .name = "DViCO FusionHDTV7 Dual Express", -#if 0 .portb = CX23885_MPEG_DVB, -#endif + .portc = CX23885_MPEG_DVB, + }, + [CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP] = { + .name = "DViCO FusionHDTV DVB-T Dual Express", + .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, }; @@ -222,6 +226,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x18ac, .subdevice = 0xd618, .card = CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP, + },{ + .subvendor = 0x18ac, + .subdevice = 0xdb78, + .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -322,32 +330,51 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) dev->name, tv.model); } -/* Tuner callback function for cx23885 boards. Currently only needed - * for HVR1500Q, which has an xc5000 tuner. - */ int cx23885_tuner_callback(void *priv, int command, int arg) { - struct cx23885_i2c *bus = priv; - struct cx23885_dev *dev = bus->dev; + struct cx23885_tsport *port = priv; + struct cx23885_dev *dev = port->dev; + u32 bitmask = 0; + + if (command == XC2028_RESET_CLK) + return 0; + + if (command != 0) { + printk(KERN_ERR "%s(): Unknown command 0x%x.\n", + __func__, command); + return -EINVAL; + } switch(dev->board) { + case CX23885_BOARD_HAUPPAUGE_HVR1400: + case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: - if(command == 0) { /* Tuner Reset Command from xc5000 */ - /* Drive the tuner into reset and out */ - cx_clear(GP0_IO, 0x00000004); - mdelay(200); - cx_set(GP0_IO, 0x00000004); - return 0; - } - else { - printk(KERN_ERR - "%s(): Unknow command.\n", __func__); - return -EINVAL; + /* Tuner Reset Command */ + if (command == 0) + bitmask = 0x04; + break; + case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: + case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: + if (command == 0) { + + /* Two identical tuners on two different i2c buses, + * we need to reset the correct gpio. */ + if (port->nr == 0) + bitmask = 0x01; + else if (port->nr == 1) + bitmask = 0x04; } break; } - return 0; /* Should never be here */ + if (bitmask) { + /* Drive the tuner into reset and back out */ + cx_clear(GP0_IO, bitmask); + mdelay(200); + cx_set(GP0_IO, bitmask); + } + + return 0; } void cx23885_gpio_setup(struct cx23885_dev *dev) @@ -439,6 +466,32 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) mdelay(20); cx_set(GP0_IO, 0x00050005); break; + case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: + /* GPIO-0 xc5000 tuner reset i2c bus 0 */ + /* GPIO-1 s5h1409 demod reset i2c bus 0 */ + /* GPIO-2 xc5000 tuner reset i2c bus 1 */ + /* GPIO-3 s5h1409 demod reset i2c bus 0 */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x000f0000); + mdelay(20); + cx_clear(GP0_IO, 0x0000000f); + mdelay(20); + cx_set(GP0_IO, 0x000f000f); + break; + case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: + /* GPIO-0 portb xc3028 reset */ + /* GPIO-1 portb zl10353 reset */ + /* GPIO-2 portc xc3028 reset */ + /* GPIO-3 portc zl10353 reset */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x000f0000); + mdelay(20); + cx_clear(GP0_IO, 0x0000000f); + mdelay(20); + cx_set(GP0_IO, 0x000f000f); + break; } } @@ -453,6 +506,9 @@ int cx23885_ir_init(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1400: /* FIXME: Implement me */ break; + case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: + request_module("ir-kbd-i2c"); + break; } return 0; @@ -490,6 +546,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) switch (dev->board) { case CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP: + case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO; diff --git a/linux/drivers/media/video/cx23885/cx23885-core.c b/linux/drivers/media/video/cx23885/cx23885-core.c index a1902d59e..0c34db9f7 100644 --- a/linux/drivers/media/video/cx23885/cx23885-core.c +++ b/linux/drivers/media/video/cx23885/cx23885-core.c @@ -77,6 +77,117 @@ LIST_HEAD(cx23885_devlist); * 0x00010ea0 0x00010xxx Free */ +static struct sram_channel cx23885_sram_channels[] = { + [SRAM_CH01] = { + .name = "VID A", + .cmds_start = 0x10000, + .ctrl_start = 0x10380, + .cdt = 0x104c0, + .fifo_start = 0x40, + .fifo_size = 0x2800, + .ptr1_reg = DMA1_PTR1, + .ptr2_reg = DMA1_PTR2, + .cnt1_reg = DMA1_CNT1, + .cnt2_reg = DMA1_CNT2, + }, + [SRAM_CH02] = { + .name = "ch2", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA2_PTR1, + .ptr2_reg = DMA2_PTR2, + .cnt1_reg = DMA2_CNT1, + .cnt2_reg = DMA2_CNT2, + }, + [SRAM_CH03] = { + .name = "TS1 B", + .cmds_start = 0x100A0, + .ctrl_start = 0x10400, + .cdt = 0x10580, + .fifo_start = 0x5000, + .fifo_size = 0x1000, + .ptr1_reg = DMA3_PTR1, + .ptr2_reg = DMA3_PTR2, + .cnt1_reg = DMA3_CNT1, + .cnt2_reg = DMA3_CNT2, + }, + [SRAM_CH04] = { + .name = "ch4", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA4_PTR1, + .ptr2_reg = DMA4_PTR2, + .cnt1_reg = DMA4_CNT1, + .cnt2_reg = DMA4_CNT2, + }, + [SRAM_CH05] = { + .name = "ch5", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH06] = { + .name = "TS2 C", + .cmds_start = 0x10140, + .ctrl_start = 0x10440, + .cdt = 0x105e0, + .fifo_start = 0x6000, + .fifo_size = 0x1000, + .ptr1_reg = DMA5_PTR1, + .ptr2_reg = DMA5_PTR2, + .cnt1_reg = DMA5_CNT1, + .cnt2_reg = DMA5_CNT2, + }, + [SRAM_CH07] = { + .name = "ch7", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA6_PTR1, + .ptr2_reg = DMA6_PTR2, + .cnt1_reg = DMA6_CNT1, + .cnt2_reg = DMA6_CNT2, + }, + [SRAM_CH08] = { + .name = "ch8", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA7_PTR1, + .ptr2_reg = DMA7_PTR2, + .cnt1_reg = DMA7_CNT1, + .cnt2_reg = DMA7_CNT2, + }, + [SRAM_CH09] = { + .name = "ch9", + .cmds_start = 0x0, + .ctrl_start = 0x0, + .cdt = 0x0, + .fifo_start = 0x0, + .fifo_size = 0x0, + .ptr1_reg = DMA8_PTR1, + .ptr2_reg = DMA8_PTR2, + .cnt1_reg = DMA8_CNT1, + .cnt2_reg = DMA8_CNT2, + }, +}; + static struct sram_channel cx23887_sram_channels[] = { [SRAM_CH01] = { .name = "VID A", @@ -105,8 +216,8 @@ static struct sram_channel cx23887_sram_channels[] = { [SRAM_CH03] = { .name = "TS1 B", .cmds_start = 0x100A0, - .ctrl_start = 0x10780, - .cdt = 0x10400, + .ctrl_start = 0x10630, + .cdt = 0x10870, .fifo_start = 0x5000, .fifo_size = 0x1000, .ptr1_reg = DMA3_PTR1, @@ -141,7 +252,7 @@ static struct sram_channel cx23887_sram_channels[] = { [SRAM_CH06] = { .name = "TS2 C", .cmds_start = 0x10140, - .ctrl_start = 0x10680, + .ctrl_start = 0x10670, .cdt = 0x108d0, .fifo_start = 0x6000, .fifo_size = 0x1000, @@ -461,6 +572,7 @@ static void cx23885_reset(struct cx23885_dev *dev) cx_write(AUDIO_INT_INT_STAT, 0xffffffff); cx_write(AUDIO_EXT_INT_STAT, 0xffffffff); cx_write(CLK_DELAY, cx_read(CLK_DELAY) & 0x80000000); + cx_write(PAD_CTRL, 0x00500300); mdelay(100); @@ -626,7 +738,6 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) atomic_inc(&dev->refcount); dev->nr = cx23885_devcount++; - dev->sram_channels = cx23887_sram_channels; sprintf(dev->name, "cx23885[%d]", dev->nr); mutex_lock(&devlist); @@ -638,11 +749,13 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->bridge = CX23885_BRIDGE_887; /* Apply a sensible clock frequency for the PCIe bridge */ dev->clk_freq = 25000000; + dev->sram_channels = cx23887_sram_channels; } else if(dev->pci->device == 0x8852) { dev->bridge = CX23885_BRIDGE_885; /* Apply a sensible clock frequency for the PCIe bridge */ dev->clk_freq = 28000000; + dev->sram_channels = cx23885_sram_channels; } else BUG(); @@ -1011,8 +1124,9 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port) port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl)); dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __func__, port->reg_dma_ctl, cx_read(port->reg_dma_ctl)); - dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__, - port->reg_src_sel, cx_read(port->reg_src_sel)); + if (port->reg_src_sel) + dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__, + port->reg_src_sel, cx_read(port->reg_src_sel)); dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __func__, port->reg_lngth, cx_read(port->reg_lngth)); dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __func__, @@ -1043,6 +1157,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port, dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__, buf->vb.width, buf->vb.height, buf->vb.field); + /* Stop the fifo and risc engine for this port */ + cx_clear(port->reg_dma_ctl, port->dma_ctl_val); + /* setup fifo + format */ cx23885_sram_channel_setup(dev, &dev->sram_channels[ port->sram_chno ], @@ -1084,7 +1201,21 @@ static int cx23885_start_dma(struct cx23885_tsport *port, cx_write(port->reg_gpcnt_ctl, 3); q->count = 1; - if (cx23885_boards[dev->board].portb & CX23885_MPEG_ENCODER) { + /* Set VIDB pins to input */ + if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) { + reg = cx_read(PAD_CTRL); + reg &= ~0x3; /* Clear TS1_OE & TS1_SOP_OE */ + cx_write(PAD_CTRL, reg); + } + + /* Set VIDC pins to input */ + if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) { + reg = cx_read(PAD_CTRL); + reg &= ~0x4; /* Clear TS2_SOP_OE */ + cx_write(PAD_CTRL, reg); + } + + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { reg = cx_read(PAD_CTRL); reg = reg & ~0x1; /* Clear TS1_OE */ @@ -1134,7 +1265,7 @@ static int cx23885_stop_dma(struct cx23885_tsport *port) cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val); cx_clear(port->reg_dma_ctl, port->dma_ctl_val); - if (cx23885_boards[dev->board].portb & CX23885_MPEG_ENCODER) { + if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { reg = cx_read(PAD_CTRL); @@ -1318,7 +1449,7 @@ void cx23885_cancel_buffers(struct cx23885_tsport *port) struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *q = &port->mpegq; - dprintk(1, "%s()\n", __FUNCTION__); + dprintk(1, "%s()\n", __func__); del_timer_sync(&q->timeout); cx23885_stop_dma(port); do_cancel_buffers(port, "cancel", 0); diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index 3c01ef2bf..c0c5b5be7 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -43,6 +43,7 @@ #include "tuner-simple.h" #include "dib7000p.h" #include "dibx000_common.h" +#include "zl10353.h" static unsigned int debug; @@ -189,13 +190,13 @@ static struct s5h1411_config dvico_s5h1411_config = { static struct xc5000_config hauppauge_hvr1500q_tunerconfig = { .i2c_address = 0x61, .if_khz = 5380, - .tuner_callback = cx23885_tuner_callback + .tuner_callback = cx23885_tuner_callback, }; static struct xc5000_config dvico_xc5000_tunerconfig = { .i2c_address = 0x64, .if_khz = 5380, - .tuner_callback = cx23885_tuner_callback + .tuner_callback = cx23885_tuner_callback, }; static struct tda829x_config tda829x_no_probe = { @@ -304,35 +305,11 @@ static struct dib7000p_config hauppauge_hvr1400_dib7000_config = { .output_mode = OUTMODE_MPEG2_SERIAL, }; -static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg) -{ - struct cx23885_tsport *port = ptr; - struct cx23885_dev *dev = port->dev; - - switch (command) { - case XC2028_TUNER_RESET: - /* Send the tuner in then out of reset */ - /* GPIO-2 xc3028 tuner */ - dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg); - - cx_set(GP0_IO, 0x00040000); - cx_clear(GP0_IO, 0x00000004); - msleep(5); - - cx_set(GP0_IO, 0x00040004); - msleep(5); - break; - case XC2028_RESET_CLK: - dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg); - break; - default: - dprintk(1, "%s: unknown command %d, arg %d\n", __func__, - command, arg); - return -EINVAL; - } - - return 0; -} +static struct zl10353_config dvico_fusionhdtv_xc3028 = { + .demod_address = 0x0f, + .if2 = 45600, + .no_tuner = 1, +}; static int dvb_register(struct cx23885_tsport *port) { @@ -415,7 +392,7 @@ static int dvb_register(struct cx23885_tsport *port) if (port->dvb.frontend != NULL) dvb_attach(xc5000_attach, port->dvb.frontend, &i2c_bus->i2c_adap, - &hauppauge_hvr1500q_tunerconfig, i2c_bus); + &hauppauge_hvr1500q_tunerconfig, port); break; case CX23885_BOARD_HAUPPAUGE_HVR1500: i2c_bus = &dev->i2c_bus[1]; @@ -427,7 +404,8 @@ static int dvb_register(struct cx23885_tsport *port) struct xc2028_config cfg = { .i2c_adap = &i2c_bus->i2c_adap, .i2c_addr = 0x61, - .callback = cx23885_hvr1500_xc3028_callback, + .video_dev = port, + .callback = cx23885_tuner_callback, }; static struct xc2028_ctrl ctl = { .fname = "xc3028-v27.fw", @@ -466,7 +444,8 @@ static int dvb_register(struct cx23885_tsport *port) struct xc2028_config cfg = { .i2c_adap = &dev->i2c_bus[1].i2c_adap, .i2c_addr = 0x64, - .callback = cx23885_hvr1500_xc3028_callback, + .video_dev = port, + .callback = cx23885_tuner_callback, }; static struct xc2028_ctrl ctl = { .fname = "xc3028L-v36.fw", @@ -494,8 +473,35 @@ static int dvb_register(struct cx23885_tsport *port) if (port->dvb.frontend != NULL) dvb_attach(xc5000_attach, port->dvb.frontend, &i2c_bus->i2c_adap, - &dvico_xc5000_tunerconfig, i2c_bus); + &dvico_xc5000_tunerconfig, port); break; + case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP: { + i2c_bus = &dev->i2c_bus[port->nr - 1]; + + port->dvb.frontend = dvb_attach(zl10353_attach, + &dvico_fusionhdtv_xc3028, + &i2c_bus->i2c_adap); + if (port->dvb.frontend != NULL) { + struct dvb_frontend *fe; + struct xc2028_config cfg = { + .i2c_adap = &i2c_bus->i2c_adap, + .i2c_addr = 0x61, + .video_dev = port, + .callback = cx23885_tuner_callback, + }; + static struct xc2028_ctrl ctl = { + .fname = "xc3028-v27.fw", + .max_len = 64, + .demod = XC3028_FE_ZARLINK456, + }; + + fe = dvb_attach(xc2028_attach, port->dvb.frontend, + &cfg); + if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + fe->ops.tuner_ops.set_config(fe, &ctl); + } + break; + } default: printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); diff --git a/linux/drivers/media/video/cx23885/cx23885-video.c b/linux/drivers/media/video/cx23885/cx23885-video.c index b3d0902e1..98a7dc1c0 100644 --- a/linux/drivers/media/video/cx23885/cx23885-video.c +++ b/linux/drivers/media/video/cx23885/cx23885-video.c @@ -787,6 +787,7 @@ static int video_open(struct inode *inode, struct file *file) enum v4l2_buf_type type = 0; int radio = 0; + lock_kernel(); list_for_each(list, &cx23885_devlist) { h = list_entry(list, struct cx23885_dev, devlist); if (h->video_dev->minor == minor) { @@ -804,16 +805,20 @@ static int video_open(struct inode *inode, struct file *file) dev = h; } } - if (NULL == dev) + if (NULL == dev) { + unlock_kernel(); return -ENODEV; + } dprintk(1, "open minor=%d radio=%d type=%s\n", minor, radio, v4l2_type_names[type]); /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); - if (NULL == fh) + if (NULL == fh) { + unlock_kernel(); return -ENOMEM; + } file->private_data = fh; fh->dev = dev; fh->radio = radio; @@ -846,6 +851,7 @@ static int video_open(struct inode *inode, struct file *file) AUDC_SET_RADIO, NULL); } #endif + unlock_kernel(); return 0; } @@ -1642,12 +1648,7 @@ static const struct file_operations video_fops = { .llseek = no_llseek, }; -static struct video_device cx23885_vbi_template; -static struct video_device cx23885_video_template = { - .name = "cx23885-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, - .fops = &video_fops, - .minor = -1, +static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1680,6 +1681,14 @@ static struct video_device cx23885_video_template = { .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif +}; + +static struct video_device cx23885_vbi_template; +static struct video_device cx23885_video_template = { + .name = "cx23885-video", + .fops = &video_fops, + .minor = -1, + .ioctl_ops = &video_ioctl_ops, .tvnorms = CX23885_NORMS, .current_norm = V4L2_STD_NTSC_M, }; @@ -1694,11 +1703,7 @@ static const struct file_operations radio_fops = { }; #if 0 -static struct video_device cx23885_radio_template = { - .name = "cx23885-radio", - .type = VID_TYPE_TUNER, - .fops = &radio_fops, - .minor = -1, +static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = radio_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, @@ -1712,6 +1717,13 @@ static struct video_device cx23885_radio_template = { .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, }; + +static struct video_device cx23885_radio_template = { + .name = "cx23885-radio", + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, + .minor = -1, +}; #endif void cx23885_video_unregister(struct cx23885_dev *dev) @@ -1758,7 +1770,6 @@ int cx23885_video_register(struct cx23885_dev *dev) memcpy(&cx23885_vbi_template, &cx23885_video_template, sizeof(cx23885_vbi_template)); strcpy(cx23885_vbi_template.name, "cx23885-vbi"); - cx23885_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER; dev->tvnorm = cx23885_video_template.current_norm; @@ -1790,7 +1801,7 @@ int cx23885_video_register(struct cx23885_dev *dev) if (TUNER_ABSENT != core->tuner_type) request_module("tuner"); - if (cx23885_boards[dev->board].audio_chip == AUDIO_CHIP_WM8775) + if (cx23885_boards[dev->board].audio_chip == V4L2_IDENT_WM8775) request_module("wm8775"); #endif diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index 9a0b4bf3a..9b76a8acf 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -65,6 +65,7 @@ #define CX23885_BOARD_HAUPPAUGE_HVR1700 8 #define CX23885_BOARD_HAUPPAUGE_HVR1400 9 #define CX23885_BOARD_DVICO_FUSIONHDTV_7_DUAL_EXP 10 +#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP 11 /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */ #define CX23885_NORMS (\ diff --git a/linux/drivers/media/video/cx25840/Kconfig b/linux/drivers/media/video/cx25840/Kconfig index 448f4cd0c..de515dada 100644 --- a/linux/drivers/media/video/cx25840/Kconfig +++ b/linux/drivers/media/video/cx25840/Kconfig @@ -1,8 +1,6 @@ config VIDEO_CX25840 tristate "Conexant CX2584x audio/video decoders" depends on VIDEO_V4L2 && I2C && EXPERIMENTAL - depends on HOTPLUG # due to FW_LOADER - select FW_LOADER ---help--- Support for the Conexant CX2584x audio/video decoders. diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c index ecd498c70..7b48e0285 100644 --- a/linux/drivers/media/video/cx25840/cx25840-core.c +++ b/linux/drivers/media/video/cx25840/cx25840-core.c @@ -51,7 +51,7 @@ MODULE_LICENSE("GPL"); static unsigned short normal_i2c[] = { 0x88 >> 1, I2C_CLIENT_END }; -int cx25840_debug; +static int cx25840_debug; module_param_named(debug,cx25840_debug, int, 0644); diff --git a/linux/drivers/media/video/cx25840/cx25840-core.h b/linux/drivers/media/video/cx25840/cx25840-core.h index f81a9a959..cd549b119 100644 --- a/linux/drivers/media/video/cx25840/cx25840-core.h +++ b/linux/drivers/media/video/cx25840/cx25840-core.h @@ -25,8 +25,6 @@ #include <linux/videodev2.h> #include <linux/i2c.h> -extern int cx25840_debug; - /* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is present in Hauppauge PVR-150 (and possibly PVR-500) cards that have certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The diff --git a/linux/drivers/media/video/cx88/Kconfig b/linux/drivers/media/video/cx88/Kconfig index 10e20d819..9dd7bdf65 100644 --- a/linux/drivers/media/video/cx88/Kconfig +++ b/linux/drivers/media/video/cx88/Kconfig @@ -33,9 +33,8 @@ config VIDEO_CX88_ALSA config VIDEO_CX88_BLACKBIRD tristate "Blackbird MPEG encoder support (cx2388x + cx23416)" - depends on VIDEO_CX88 && HOTPLUG + depends on VIDEO_CX88 select VIDEO_CX2341X - select FW_LOADER ---help--- This adds support for MPEG encoder cards based on the Blackbird reference design, using the Conexant 2388x diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c index 4b780c237..0cd510814 100644 --- a/linux/drivers/media/video/cx88/cx88-blackbird.c +++ b/linux/drivers/media/video/cx88/cx88-blackbird.c @@ -1076,12 +1076,15 @@ static int mpeg_open(struct inode *inode, struct file *file) struct cx8802_driver *drv = NULL; int err; + lock_kernel(); dev = cx8802_get_device(inode); dprintk( 1, "%s\n", __func__); - if (dev == NULL) + if (dev == NULL) { + unlock_kernel(); return -ENODEV; + } /* Make sure we can acquire the hardware */ drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD); @@ -1096,6 +1099,7 @@ static int mpeg_open(struct inode *inode, struct file *file) if (blackbird_initialize_codec(dev) < 0) { if (drv) drv->request_release(drv); + unlock_kernel(); return -EINVAL; } dprintk(1,"open minor=%d\n",minor); @@ -1105,6 +1109,7 @@ static int mpeg_open(struct inode *inode, struct file *file) if (NULL == fh) { if (drv) drv->request_release(drv); + unlock_kernel(); return -ENOMEM; } file->private_data = fh; @@ -1120,6 +1125,7 @@ static int mpeg_open(struct inode *inode, struct file *file) /* FIXME: locking against other video device */ cx88_set_scale(dev->core, dev->width, dev->height, fh->mpegq.field); + unlock_kernel(); return 0; } @@ -1194,12 +1200,7 @@ static const struct file_operations mpeg_fops = .llseek = no_llseek, }; -static struct video_device cx8802_mpeg_template = -{ - .name = "cx8802", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES|VID_TYPE_MPEG_ENCODER, - .fops = &mpeg_fops, - .minor = -1, +static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_querymenu = vidioc_querymenu, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, @@ -1227,6 +1228,13 @@ static struct video_device cx8802_mpeg_template = .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_s_std = vidioc_s_std, +}; + +static struct video_device cx8802_mpeg_template = { + .name = "cx8802", + .fops = &mpeg_fops, + .ioctl_ops = &mpeg_ioctl_ops, + .minor = -1, .tvnorms = CX88_NORMS, .current_norm = V4L2_STD_NTSC_M, }; diff --git a/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c index 9329dbf6a..871ba1992 100644 --- a/linux/drivers/media/video/cx88/cx88-cards.c +++ b/linux/drivers/media/video/cx88/cx88-cards.c @@ -1381,7 +1381,7 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, .tda9887_conf = TDA9887_PRESENT, - .audio_chip = AUDIO_CHIP_WM8775, + .audio_chip = V4L2_IDENT_WM8775, .input = {{ .type = CX88_VMUX_TELEVISION, .vmux = 0, diff --git a/linux/drivers/media/video/cx88/cx88-video.c b/linux/drivers/media/video/cx88/cx88-video.c index f26232345..3a7a9ed17 100644 --- a/linux/drivers/media/video/cx88/cx88-video.c +++ b/linux/drivers/media/video/cx88/cx88-video.c @@ -449,7 +449,7 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) the initialization. Some boards may use different routes for different inputs. HVR-1300 surely does */ if (core->board.audio_chip && - core->board.audio_chip == AUDIO_CHIP_WM8775) { + core->board.audio_chip == V4L2_IDENT_WM8775) { struct v4l2_routing route; route.input = INPUT(input).audioroute; @@ -999,6 +999,7 @@ static int video_open(struct inode *inode, struct file *file) enum v4l2_buf_type type = 0; int radio = 0; + lock_kernel(); list_for_each_entry(h, &cx8800_devlist, devlist) { if (h->video_dev->minor == minor) { dev = h; @@ -1014,8 +1015,10 @@ static int video_open(struct inode *inode, struct file *file) dev = h; } } - if (NULL == dev) + if (NULL == dev) { + unlock_kernel(); return -ENODEV; + } core = dev->core; @@ -1024,8 +1027,10 @@ static int video_open(struct inode *inode, struct file *file) /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) + if (NULL == fh) { + unlock_kernel(); return -ENOMEM; + } file->private_data = fh; fh->dev = dev; fh->radio = radio; @@ -1058,6 +1063,7 @@ static int video_open(struct inode *inode, struct file *file) cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1); cx88_call_i2c_clients(core,AUDC_SET_RADIO,NULL); } + unlock_kernel(); return 0; } @@ -1953,13 +1959,7 @@ static const struct file_operations video_fops = .llseek = no_llseek, }; -static struct video_device cx8800_vbi_template; -static struct video_device cx8800_video_template = -{ - .name = "cx8800-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER|VID_TYPE_SCALES, - .fops = &video_fops, - .minor = -1, +static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1992,6 +1992,15 @@ static struct video_device cx8800_video_template = .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif +}; + +static struct video_device cx8800_vbi_template; + +static struct video_device cx8800_video_template = { + .name = "cx8800-video", + .fops = &video_fops, + .minor = -1, + .ioctl_ops = &video_ioctl_ops, .tvnorms = CX88_NORMS, .current_norm = V4L2_STD_NTSC_M, }; @@ -2006,12 +2015,7 @@ static const struct file_operations radio_fops = .llseek = no_llseek, }; -static struct video_device cx8800_radio_template = -{ - .name = "cx8800-radio", - .type = VID_TYPE_TUNER, - .fops = &radio_fops, - .minor = -1, +static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = radio_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, @@ -2030,6 +2034,13 @@ static struct video_device cx8800_radio_template = #endif }; +static struct video_device cx8800_radio_template = { + .name = "cx8800-radio", + .fops = &radio_fops, + .minor = -1, + .ioctl_ops = &radio_ioctl_ops, +}; + /* ----------------------------------------------------------- */ static void cx8800_unregister_video(struct cx8800_dev *dev) @@ -2101,7 +2112,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, memcpy( &cx8800_vbi_template, &cx8800_video_template, sizeof(cx8800_vbi_template) ); strcpy(cx8800_vbi_template.name,"cx8800-vbi"); - cx8800_vbi_template.type = VID_TYPE_TELETEXT|VID_TYPE_TUNER; /* initialize driver struct */ #if 0 @@ -2141,7 +2151,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, /* load and configure helper modules */ - if (core->board.audio_chip == AUDIO_CHIP_WM8775) + if (core->board.audio_chip == V4L2_IDENT_WM8775) request_module("wm8775"); switch (core->boardnr) { diff --git a/linux/drivers/media/video/cx88/cx88.h b/linux/drivers/media/video/cx88/cx88.h index 3e4b80617..751176e7a 100644 --- a/linux/drivers/media/video/cx88/cx88.h +++ b/linux/drivers/media/video/cx88/cx88.h @@ -29,8 +29,8 @@ #include <media/tuner.h> #include <media/tveeprom.h> #include <media/videobuf-dma-sg.h> +#include <media/v4l2-chip-ident.h> #include <media/cx2341x.h> -#include <media/audiochip.h> #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) #include <media/videobuf-dvb.h> #endif @@ -253,7 +253,7 @@ struct cx88_board { struct cx88_input input[MAX_CX88_INPUT]; struct cx88_input radio; enum cx88_board_type mpeg; - enum audiochip audio_chip; + unsigned int audio_chip; }; struct cx88_subid { diff --git a/linux/drivers/media/video/dpc7146.c b/linux/drivers/media/video/dpc7146.c deleted file mode 100644 index 4bfb3076b..000000000 --- a/linux/drivers/media/video/dpc7146.c +++ /dev/null @@ -1,409 +0,0 @@ -/* - 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 - 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. -*/ - -#define DEBUG_VARIABLE debug - -#include <media/saa7146_vv.h> -#include <linux/video_decoder.h> /* for saa7111a */ -#include "compat.h" - -#define I2C_SAA7111A 0x24 - -/* All unused bytes are reserverd. */ -#define SAA711X_CHIP_VERSION 0x00 -#define SAA711X_ANALOG_INPUT_CONTROL_1 0x02 -#define SAA711X_ANALOG_INPUT_CONTROL_2 0x03 -#define SAA711X_ANALOG_INPUT_CONTROL_3 0x04 -#define SAA711X_ANALOG_INPUT_CONTROL_4 0x05 -#define SAA711X_HORIZONTAL_SYNC_START 0x06 -#define SAA711X_HORIZONTAL_SYNC_STOP 0x07 -#define SAA711X_SYNC_CONTROL 0x08 -#define SAA711X_LUMINANCE_CONTROL 0x09 -#define SAA711X_LUMINANCE_BRIGHTNESS 0x0A -#define SAA711X_LUMINANCE_CONTRAST 0x0B -#define SAA711X_CHROMA_SATURATION 0x0C -#define SAA711X_CHROMA_HUE_CONTROL 0x0D -#define SAA711X_CHROMA_CONTROL 0x0E -#define SAA711X_FORMAT_DELAY_CONTROL 0x10 -#define SAA711X_OUTPUT_CONTROL_1 0x11 -#define SAA711X_OUTPUT_CONTROL_2 0x12 -#define SAA711X_OUTPUT_CONTROL_3 0x13 -#define SAA711X_V_GATE_1_START 0x15 -#define SAA711X_V_GATE_1_STOP 0x16 -#define SAA711X_V_GATE_1_MSB 0x17 -#define SAA711X_TEXT_SLICER_STATUS 0x1A -#define SAA711X_DECODED_BYTES_OF_TS_1 0x1B -#define SAA711X_DECODED_BYTES_OF_TS_2 0x1C -#define SAA711X_STATUS_BYTE 0x1F - -#define DPC_BOARD_CAN_DO_VBI(dev) (dev->revision != 0) - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "debug verbosity"); - -static int dpc_num; - -#define DPC_INPUTS 2 -static struct v4l2_input dpc_inputs[DPC_INPUTS] = { - { 0, "Port A", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, - { 1, "Port B", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 }, -}; - -#define DPC_AUDIOS 0 - -static struct saa7146_extension_ioctls ioctls[] = { - { VIDIOC_G_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_INPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_ENUMINPUT, SAA7146_EXCLUSIVE }, - { VIDIOC_S_STD, SAA7146_AFTER }, - { 0, 0 } -}; - -struct dpc -{ - struct video_device *video_dev; - struct video_device *vbi_dev; - - struct i2c_adapter i2c_adapter; - struct i2c_client *saa7111a; - - int cur_input; /* current input */ -}; - -static int dpc_check_clients(struct device *dev, void *data) -{ - struct dpc* dpc = data; - struct i2c_client *client = i2c_verify_client(dev); - - if( !client ) - return 0; - - if( I2C_SAA7111A == client->addr ) - dpc->saa7111a = client; - - return 0; -} - -/* fixme: add vbi stuff here */ -static int dpc_probe(struct saa7146_dev* dev) -{ - struct dpc* dpc = NULL; - - dpc = kzalloc(sizeof(struct dpc), GFP_KERNEL); - if( NULL == dpc ) { - printk("dpc_v4l2.o: dpc_probe: not enough kernel memory.\n"); - return -ENOMEM; - } - - /* FIXME: enable i2c-port pins, video-port-pins - video port pins should be enabled here ?! */ - saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); - - dpc->i2c_adapter = (struct i2c_adapter) { - .class = I2C_CLASS_TV_ANALOG, - .name = "dpc7146", - }; - saa7146_i2c_adapter_prepare(dev, &dpc->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); - if(i2c_add_adapter(&dpc->i2c_adapter) < 0) { - DEB_S(("cannot register i2c-device. skipping.\n")); - kfree(dpc); - return -EFAULT; - } - - /* loop through all i2c-devices on the bus and look who is there */ - device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients); - - /* check if all devices are present */ - if (!dpc->saa7111a) { - 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")); - - /* we store the pointer in our private data field */ - dev->ext_priv = dpc; - - return 0; -} - -/* 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. - the capture engine would badly fail, because no valid signal arrives on the - saa7146, thus leading to timeouts and stuff. */ -static int dpc_init_done(struct saa7146_dev* dev) -{ - struct dpc* dpc = (struct dpc*)dev->ext_priv; - - DEB_D(("dpc_v4l2.o: dpc_init_done called.\n")); - - /* initialize the helper ics to useful values */ - i2c_smbus_write_byte_data(dpc->saa7111a, 0x00, 0x11); - - i2c_smbus_write_byte_data(dpc->saa7111a, 0x02, 0xc0); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x03, 0x30); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x04, 0x00); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x05, 0x00); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x06, 0xde); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x07, 0xad); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x08, 0xa8); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x09, 0x00); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x0a, 0x80); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x0b, 0x47); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x0c, 0x40); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x0d, 0x00); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x0e, 0x03); - - i2c_smbus_write_byte_data(dpc->saa7111a, 0x10, 0xd0); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x11, 0x1c); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x12, 0xc1); - i2c_smbus_write_byte_data(dpc->saa7111a, 0x13, 0x30); - - i2c_smbus_write_byte_data(dpc->saa7111a, 0x1f, 0x81); - - return 0; -} - -static struct saa7146_ext_vv vv_data; - -/* this function only gets called when the probing was successful */ -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 - already did this in "dpc_vl42_probe" */ - - saa7146_vv_init(dev,&vv_data); - if( 0 != saa7146_register_device(&dpc->video_dev, dev, "dpc", VFL_TYPE_GRABBER)) { - 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)) { - ERR(("cannot register vbi v4l2 device. skipping.\n")); - } - } - - i2c_use_client(dpc->saa7111a); - - 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); - - saa7146_unregister_device(&dpc->video_dev,dev); - if( 0 != DPC_BOARD_CAN_DO_VBI(dev)) { - saa7146_unregister_device(&dpc->vbi_dev,dev); - } - saa7146_vv_release(dev); - - dpc_num--; - - i2c_del_adapter(&dpc->i2c_adapter); - kfree(dpc); - return 0; -} - -#ifdef axa -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) -{ - struct saa7146_dev *dev = fh->dev; - struct dpc* dpc = (struct dpc*)dev->ext_priv; -/* - 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 >= 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)); - return 0; - } - case VIDIOC_G_INPUT: - { - int *input = (int *)arg; - *input = dpc->cur_input; - - DEB_D(("dpc_v4l2.o: VIDIOC_G_INPUT: %d\n",*input)); - return 0; - } - case VIDIOC_S_INPUT: - { - int input = *(int *)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: -/* - DEB_D(("dpc_v4l2.o: v4l2_ioctl does not handle this ioctl.\n")); -*/ - return -ENOIOCTLCMD; - } - return 0; -} - -static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) -{ - return 0; -} - -static struct saa7146_standard standard[] = { - { - .name = "PAL", .id = V4L2_STD_PAL, - .v_offset = 0x17, .v_field = 288, - .h_offset = 0x14, .h_pixels = 680, - .v_max_out = 576, .h_max_out = 768, - }, { - .name = "NTSC", .id = V4L2_STD_NTSC, - .v_offset = 0x16, .v_field = 240, - .h_offset = 0x06, .h_pixels = 708, - .v_max_out = 480, .h_max_out = 640, - }, { - .name = "SECAM", .id = V4L2_STD_SECAM, - .v_offset = 0x14, .v_field = 288, - .h_offset = 0x14, .h_pixels = 720, - .v_max_out = 576, .h_max_out = 768, - } -}; - -static struct saa7146_extension extension; - -static struct saa7146_pci_extension_data dpc = { - .ext_priv = "Multimedia eXtension Board", - .ext = &extension, -}; - -static struct pci_device_id pci_tbl[] = { - { - .vendor = PCI_VENDOR_ID_PHILIPS, - .device = PCI_DEVICE_ID_PHILIPS_SAA7146, - .subvendor = 0x0000, - .subdevice = 0x0000, - .driver_data = (unsigned long)&dpc, - }, { - .vendor = 0, - } -}; - -MODULE_DEVICE_TABLE(pci, pci_tbl); - -static struct saa7146_ext_vv vv_data = { - .inputs = DPC_INPUTS, - .capabilities = V4L2_CAP_VBI_CAPTURE, - .stds = &standard[0], - .num_stds = sizeof(standard)/sizeof(struct saa7146_standard), - .std_callback = &std_callback, - .ioctls = &ioctls[0], - .ioctl = dpc_ioctl, -}; - -static struct saa7146_extension extension = { - .name = "dpc7146 demonstration board", - .flags = SAA7146_USE_I2C_IRQ, - - .pci_tbl = &pci_tbl[0], - .module = THIS_MODULE, - - .probe = dpc_probe, - .attach = dpc_attach, - .detach = dpc_detach, - - .irq_mask = 0, - .irq_func = NULL, -}; - -static int __init dpc_init_module(void) -{ - if( 0 != saa7146_register_extension(&extension)) { - DEB_S(("failed to register extension.\n")); - return -ENODEV; - } - - return 0; -} - -static void __exit dpc_cleanup_module(void) -{ - saa7146_unregister_extension(&extension); -} - -module_init(dpc_init_module); -module_exit(dpc_cleanup_module); - -MODULE_DESCRIPTION("video4linux-2 driver for the 'dpc7146 demonstration board'"); -MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); -MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c index 871d81242..eae5ebd0e 100644 --- a/linux/drivers/media/video/em28xx/em28xx-cards.c +++ b/linux/drivers/media/video/em28xx/em28xx-cards.c @@ -33,8 +33,8 @@ #include <media/saa7115.h> #include <media/tvp5150.h> #include <media/tveeprom.h> -#include <media/audiochip.h> #include <media/v4l2-common.h> +#include <media/v4l2-chip-ident.h> #include "em28xx.h" @@ -53,6 +53,15 @@ struct em28xx_hash_table { }; struct em28xx_board em28xx_boards[] = { + [EM2750_BOARD_UNKNOWN] = { + .name = "Unknown EM2750/EM2751 webcam grabber", + .vchannels = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = 0, + } }, + }, [EM2800_BOARD_UNKNOWN] = { .name = "Unknown EM2800 video grabber", .is_em2800 = 1, @@ -74,6 +83,39 @@ struct em28xx_board em28xx_boards[] = { .is_em2800 = 0, .tuner_type = TUNER_ABSENT, }, + [EM2750_BOARD_DLCW_130] = { + /* Beijing Huaqi Information Digital Technology Co., Ltd */ + .name = "Huaqi DLCW-130", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = 0, + } }, + }, + [EM2800_BOARD_KWORLD_USB2800] = { + .name = "Kworld USB2800", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .is_em2800 = 1, + .vchannels = 3, + .tuner_type = TUNER_PHILIPS_FCV1236D, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, [EM2820_BOARD_KWORLD_PVRTV2800RF] = { .name = "Kworld PVR TV 2800 RF", .is_em2800 = 0, @@ -152,6 +194,376 @@ struct em28xx_board em28xx_boards[] = { MSP_DSP_IN_SCART, MSP_DSP_IN_SCART), } }, }, + [EM2820_BOARD_DLINK_USB_TV] = { + .name = "D-Link DUB-T210 TV Tuner", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .is_em2800 = 0, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 1, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_HERCULES_SMART_TV_USB2] = { + .name = "Hercules Smart TV USB 2.0", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 1, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_PINNACLE_USB_2_FM1216ME] = { + .name = "Pinnacle PCTV USB 2 (Philips FM1216ME)", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .is_em2800 = 0, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_GADMEI_UTV310] = { + .name = "Gadmei UTV310", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_TNF_5335MF, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE] = { + .name = "Leadtek Winfast USB II Deluxe", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7114, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = 2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = 9, + .amux = 1, + } }, + }, + [EM2820_BOARD_PINNACLE_DVC_100] = { + .name = "Pinnacle Dazzle DVC 100", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2820_BOARD_VIDEOLOGY_20K14XUSB] = { + .name = "Videology 20K14XUSB USB2.0", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = 0, + } }, + }, + [EM2821_BOARD_PROLINK_PLAYTV_USB2] = { + .name = "SIIG AVTuner-PVR/Prolink PlayTV USB 2.0", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .is_em2800 = 0, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, /* unknown? */ + .tda9887_conf = TDA9887_PRESENT, /* unknown? */ + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 1, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2821_BOARD_SUPERCOMP_USB_2] = { + .name = "Supercomp USB 2.0 TV", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .is_em2800 = 0, + .tuner_type = TUNER_PHILIPS_FM1236_MK3, + .tda9887_conf = TDA9887_PRESENT | + TDA9887_PORT1_ACTIVE | + TDA9887_PORT2_ACTIVE, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 1, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2821_BOARD_USBGEAR_VD204] = { + .name = "Usbgear VD204v9", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 2, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2860_BOARD_NETGMBH_CAM] = { + /* Beijing Huaqi Information Digital Technology Co., Ltd */ + .name = "NetGMBH Cam", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 1, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = 0, + .amux = 0, + } }, + }, + [EM2860_BOARD_TYPHOON_DVD_MAKER] = { + .name = "Typhoon DVD Maker", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 2, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2860_BOARD_GADMEI_UTV330] = { + .name = "Gadmei UTV330", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_TNF_5335MF, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = SAA7115_COMPOSITE2, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, + [EM2860_BOARD_TERRATEC_HYBRID_XS] = { + .name = "Terratec Cinergy A Hybrid XS", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2861_BOARD_KWORLD_PVRTV_300U] = { + .name = "KWorld PVRTV 300U", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2861_BOARD_YAKUMO_MOVIE_MIXER] = { + .name = "Yakumo MovieMixer", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2861_BOARD_PLEXTOR_PX_TV100U] = { + .name = "Plextor ConvertX PX-TV100U", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_TNF_5335MF, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2870_BOARD_TERRATEC_XS] = { + .name = "Terratec Cinergy T XS", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_XC2028, + }, + [EM2870_BOARD_TERRATEC_XS_MT2060] = { + .name = "Terratec Cinergy T XS (MT2060)", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* MT2060 */ + }, + [EM2870_BOARD_KWORLD_350U] = { + .name = "Kworld 350 U DVB-T", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_XC2028, + }, + [EM2870_BOARD_KWORLD_355U] = { + .name = "Kworld 355 U DVB-T", + .valid = EM28XX_BOARD_NOT_VALIDATED, + }, + [EM2870_BOARD_PINNACLE_PCTV_DVB] = { + .name = "Pinnacle PCTV DVB-T", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* MT2060 */ + }, + [EM2870_BOARD_COMPRO_VIDEOMATE] = { + .name = "Compro, VideoMate U3", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .tuner_type = TUNER_ABSENT, /* MT2060 */ + }, + [EM2880_BOARD_TERRATEC_HYBRID_XS_FR] = { + .name = "Terratec Hybrid XS Secam", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .has_msp34xx = 1, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = { .name = "Hauppauge WinTV HVR 900", .vchannels = 3, @@ -195,7 +607,7 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, - [EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950] = { + [EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950] = { .name = "Hauppauge WinTV HVR 950", .vchannels = 3, .tda9887_conf = TDA9887_PRESENT, @@ -241,12 +653,36 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, + [EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600] = { + .name = "AMD ATI TV Wonder HD 600", + .vchannels = 3, + .tda9887_conf = TDA9887_PRESENT, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .has_12mhz_i2s = 1, + .has_dvb = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, [EM2880_BOARD_TERRATEC_HYBRID_XS] = { .name = "Terratec Hybrid XS", .vchannels = 3, .tda9887_conf = TDA9887_PRESENT, .tuner_type = TUNER_XC2028, .decoder = EM28XX_TVP5150, + .has_dvb = 1, .input = { { .type = EM28XX_VMUX_TELEVISION, .vmux = TVP5150_COMPOSITE0, @@ -329,6 +765,21 @@ struct em28xx_board em28xx_boards[] = { .amux = 1, } }, }, + [EM2800_BOARD_GRABBEEX_USB2800] = { + .name = "eMPIA Technology, Inc. GrabBeeX+ Video Encoder", + .is_em2800 = 1, + .vchannels = 2, + .decoder = EM28XX_SAA7113, + .input = { { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = SAA7115_COMPOSITE0, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = SAA7115_SVIDEO3, + .amux = 1, + } }, + }, [EM2800_BOARD_LEADTEK_WINFAST_USBII] = { .name = "Leadtek Winfast USB II", .is_em2800 = 1, @@ -440,13 +891,233 @@ struct em28xx_board em28xx_boards[] = { .amux = 0, } }, }, + [EM2880_BOARD_MSI_DIGIVOX_AD] = { + .name = "MSI DigiVox A/D", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2880_BOARD_MSI_DIGIVOX_AD_II] = { + .name = "MSI DigiVox A/D II", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2880_BOARD_KWORLD_DVB_305U] = { + .name = "KWorld DVB-T 305U", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2880_BOARD_KWORLD_DVB_310U] = { + .name = "KWorld DVB-T 310U", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2881_BOARD_DNT_DA2_HYBRID] = { + .name = "DNT DA2 Hybrid", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2881_BOARD_PINNACLE_HYBRID_PRO] = { + .name = "Pinnacle Hybrid Pro", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2882_BOARD_PINNACLE_HYBRID_PRO] = { + .name = "Pinnacle Hybrid Pro (2)", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .mts_firmware = 1, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2882_BOARD_KWORLD_VS_DVBT] = { + .name = "Kworld VS-DVB-T 323UR", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2882_BOARD_TERRATEC_HYBRID_XS] = { + .name = "Terratec Hybrid XS (em2882)", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2883_BOARD_KWORLD_HYBRID_A316] = { + .name = "Kworld PlusTV HD Hybrid 330", + .valid = EM28XX_BOARD_NOT_VALIDATED, + .vchannels = 3, + .is_em2800 = 0, + .tuner_type = TUNER_XC2028, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = 0, + }, { + .type = EM28XX_VMUX_COMPOSITE1, + .vmux = TVP5150_COMPOSITE1, + .amux = 1, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = 1, + } }, + }, + [EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU] = { + .name = "Compro VideoMate ForYou/Stereo", + .vchannels = 2, + .tuner_type = TUNER_LG_PAL_NEW_TAPC, + .tda9887_conf = TDA9887_PRESENT, + .decoder = EM28XX_TVP5150, + .input = { { + .type = EM28XX_VMUX_TELEVISION, + .vmux = TVP5150_COMPOSITE0, + .amux = EM28XX_AMUX_LINE_IN, + }, { + .type = EM28XX_VMUX_SVIDEO, + .vmux = TVP5150_SVIDEO, + .amux = EM28XX_AMUX_LINE_IN, + } }, + }, }; const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards); /* table of devices that work with this driver */ struct usb_device_id em28xx_id_table [] = { { USB_DEVICE(0xeb1a, 0x2750), - .driver_info = EM2820_BOARD_UNKNOWN }, + .driver_info = EM2750_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2751), + .driver_info = EM2750_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2800), .driver_info = EM2800_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2820), @@ -463,36 +1134,81 @@ struct usb_device_id em28xx_id_table [] = { .driver_info = EM2820_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2883), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0xe300), + .driver_info = EM2861_BOARD_KWORLD_PVRTV_300U }, + { USB_DEVICE(0xeb1a, 0xe305), + .driver_info = EM2880_BOARD_KWORLD_DVB_305U }, + { USB_DEVICE(0xeb1a, 0xe310), + .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD }, + { USB_DEVICE(0xeb1a, 0xa316), + .driver_info = EM2883_BOARD_KWORLD_HYBRID_A316 }, + { USB_DEVICE(0xeb1a, 0xe320), + .driver_info = EM2880_BOARD_MSI_DIGIVOX_AD_II }, + { USB_DEVICE(0xeb1a, 0xe323), + .driver_info = EM2882_BOARD_KWORLD_VS_DVBT }, + { USB_DEVICE(0xeb1a, 0xe350), + .driver_info = EM2870_BOARD_KWORLD_350U }, + { USB_DEVICE(0xeb1a, 0xe355), + .driver_info = EM2870_BOARD_KWORLD_355U }, + { USB_DEVICE(0xeb1a, 0x2801), + .driver_info = EM2800_BOARD_GRABBEEX_USB2800 }, + { USB_DEVICE(0xeb1a, 0xe357), + .driver_info = EM2870_BOARD_KWORLD_355U }, { USB_DEVICE(0x0ccd, 0x0036), .driver_info = EM2820_BOARD_TERRATEC_CINERGY_250 }, - { USB_DEVICE(0x2304, 0x0208), - .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, + { USB_DEVICE(0x0ccd, 0x004c), + .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS_FR }, + { USB_DEVICE(0x0ccd, 0x004f), + .driver_info = EM2860_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x005e), + .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x0042), + .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, + { USB_DEVICE(0x0ccd, 0x0043), + .driver_info = EM2870_BOARD_TERRATEC_XS }, + { USB_DEVICE(0x0ccd, 0x0047), + .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, + { USB_DEVICE(0x185b, 0x2870), + .driver_info = EM2870_BOARD_COMPRO_VIDEOMATE }, + { USB_DEVICE(0x185b, 0x2041), + .driver_info = EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU }, { USB_DEVICE(0x2040, 0x4200), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, { USB_DEVICE(0x2040, 0x4201), .driver_info = EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 }, - { USB_DEVICE(0x2304, 0x0207), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, - { USB_DEVICE(0x2304, 0x021a), - .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, - { USB_DEVICE(0x2304, 0x0227), - .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, { USB_DEVICE(0x2040, 0x6500), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 }, { USB_DEVICE(0x2040, 0x6502), .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 }, { USB_DEVICE(0x2040, 0x6513), /* HCW HVR-980 */ - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x2040, 0x6517), /* HP HVR-950 */ - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x2040, 0x651b), /* RP HVR-950 */ - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, { USB_DEVICE(0x2040, 0x651f), /* HCW HVR-850 */ - .driver_info = EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 }, - { USB_DEVICE(0x0ccd, 0x0042), - .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS }, - { USB_DEVICE(0x0ccd, 0x0047), - .driver_info = EM2880_BOARD_TERRATEC_PRODIGY_XS }, + .driver_info = EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 }, + { USB_DEVICE(0x0438, 0xb002), + .driver_info = EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 }, + { USB_DEVICE(0x2001, 0xf112), + .driver_info = EM2820_BOARD_DLINK_USB_TV }, + { USB_DEVICE(0x2304, 0x0207), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2304, 0x0208), + .driver_info = EM2820_BOARD_PINNACLE_USB_2 }, + { USB_DEVICE(0x2304, 0x021a), + .driver_info = EM2820_BOARD_PINNACLE_DVC_90 }, + { USB_DEVICE(0x2304, 0x0226), + .driver_info = EM2882_BOARD_PINNACLE_HYBRID_PRO }, + { USB_DEVICE(0x2304, 0x0227), + .driver_info = EM2880_BOARD_PINNACLE_PCTV_HD_PRO }, + { USB_DEVICE(0x0413, 0x6023), + .driver_info = EM2800_BOARD_LEADTEK_WINFAST_USBII }, + { USB_DEVICE(0x093b, 0xa005), + .driver_info = EM2861_BOARD_PLEXTOR_PX_TV100U }, +#if 0 + EM2880_BOARD_KWORLD_DVB_310U }, +#endif { }, }; MODULE_DEVICE_TABLE(usb, em28xx_id_table); @@ -501,6 +1217,18 @@ MODULE_DEVICE_TABLE(usb, em28xx_id_table); * Reset sequences for analog/digital modes */ +/* Reset for the most [analog] boards */ +static struct em28xx_reg_seq default_analog[] = { + {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Reset for the most [digital] boards */ +static struct em28xx_reg_seq default_digital[] = { + {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + /* Board Hauppauge WinTV HVR 900 analog */ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = { {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10}, @@ -516,14 +1244,42 @@ static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = { { -1, -1, -1, -1}, }; -/* Board Hauppauge WinTV HVR 900 tuner_callback */ -static struct em28xx_reg_seq hauppauge_wintv_hvr_900_tuner_callback[] = { +/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ +static struct em28xx_reg_seq em2880_msi_digivox_ad_analog[] = { + {EM28XX_R08_GPIO, 0x69, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Boards - EM2880 MSI DIGIVOX AD and EM2880_BOARD_MSI_DIGIVOX_AD_II */ +static struct em28xx_reg_seq em2880_msi_digivox_ad_digital[] = { + {EM28XX_R08_GPIO, 0x6a, ~EM_GPIO_4, 10}, + { -1, -1, -1, -1}, +}; + +/* Board - EM2870 Kworld 355u + Analog - No input analog */ +static struct em28xx_reg_seq em2870_kworld_355u_digital[] = { + {EM2880_R04_GPO, 0x01, 0xff, 10}, + { -1, -1, -1, -1}, +}; + +/* Callback for the most boards */ +static struct em28xx_reg_seq default_callback[] = { {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10}, {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10}, { -1, -1, -1, -1}, }; +/* Callback for EM2882 TERRATEC HYBRID XS */ +static struct em28xx_reg_seq em2882_terratec_hybrid_xs_digital[] = { + {EM28XX_R08_GPIO, 0x2e, 0xff, 6}, + {EM28XX_R08_GPIO, 0x3e, ~EM_GPIO_4, 6}, + {EM2880_R04_GPO, 0x04, 0xff, 10}, + {EM2880_R04_GPO, 0x0c, 0xff, 10}, + { -1, -1, -1, -1}, +}; + /* * EEPROM hash table for devices with generic USB IDs */ @@ -570,6 +1326,7 @@ static void em28xx_set_model(struct em28xx *dev) dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480; dev->has_dvb = em28xx_boards[dev->model].has_dvb; dev->has_snapshot_button = em28xx_boards[dev->model].has_snapshot_button; + dev->valid = em28xx_boards[dev->model].valid; } /* Since em28xx_pre_card_setup() requires a proper dev->model, @@ -605,19 +1362,171 @@ void em28xx_pre_card_setup(struct em28xx *dev) case EM2880_BOARD_TERRATEC_PRODIGY_XS: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: - case EM2880_BOARD_TERRATEC_HYBRID_XS: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2860_BOARD_TERRATEC_HYBRID_XS: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: + case EM2882_BOARD_PINNACLE_HYBRID_PRO: + case EM2883_BOARD_KWORLD_HYBRID_A316: + case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + msleep(50); + + /* Sets GPO/GPIO sequences for this device */ + dev->analog_gpio = hauppauge_wintv_hvr_900_analog; + dev->digital_gpio = hauppauge_wintv_hvr_900_digital; + dev->tun_analog_gpio = default_callback; + dev->tun_digital_gpio = default_callback; + break; + + case EM2882_BOARD_TERRATEC_HYBRID_XS: em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); msleep(50); + /* should be added ir_codes here */ + /* Sets GPO/GPIO sequences for this device */ dev->analog_gpio = hauppauge_wintv_hvr_900_analog; dev->digital_gpio = hauppauge_wintv_hvr_900_digital; - dev->tun_analog_gpio = hauppauge_wintv_hvr_900_tuner_callback; - dev->tun_digital_gpio = hauppauge_wintv_hvr_900_tuner_callback; + dev->tun_analog_gpio = default_callback; + dev->tun_digital_gpio = em2882_terratec_hybrid_xs_digital; + break; + + case EM2880_BOARD_TERRATEC_HYBRID_XS_FR: + case EM2880_BOARD_TERRATEC_HYBRID_XS: + case EM2870_BOARD_TERRATEC_XS: + case EM2881_BOARD_PINNACLE_HYBRID_PRO: + case EM2880_BOARD_KWORLD_DVB_310U: + case EM2870_BOARD_KWORLD_350U: + case EM2881_BOARD_DNT_DA2_HYBRID: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + msleep(50); + + /* NOTE: EM2881_DNT_DA2_HYBRID spend 140 msleep for digital + and analog commands. If this commands doesn't work, + add this timer. */ + + /* Sets GPO/GPIO sequences for this device */ + dev->analog_gpio = default_analog; + dev->digital_gpio = default_digital; + dev->tun_analog_gpio = default_callback; + dev->tun_digital_gpio = default_callback; + break; + + case EM2880_BOARD_MSI_DIGIVOX_AD: + case EM2880_BOARD_MSI_DIGIVOX_AD_II: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + msleep(50); + + /* Sets GPO/GPIO sequences for this device */ + dev->analog_gpio = em2880_msi_digivox_ad_analog; + dev->digital_gpio = em2880_msi_digivox_ad_digital; + dev->tun_analog_gpio = default_callback; + dev->tun_digital_gpio = default_callback; + break; + + case EM2750_BOARD_UNKNOWN: + case EM2750_BOARD_DLCW_130: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x0a", 1); + break; + + case EM2861_BOARD_PLEXTOR_PX_TV100U: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* FIXME guess */ + /* Turn on analog audio output */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); + break; + + case EM2861_BOARD_KWORLD_PVRTV_300U: + case EM2880_BOARD_KWORLD_DVB_305U: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x4c", 1); + msleep(10); + em28xx_write_regs(dev, 0x08, "\x6d", 1); + msleep(10); + em28xx_write_regs(dev, 0x08, "\x7d", 1); + msleep(10); + break; + + case EM2870_BOARD_KWORLD_355U: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + msleep(50); + + /* Sets GPO/GPIO sequences for this device */ + dev->digital_gpio = em2870_kworld_355u_digital; + break; + + case EM2870_BOARD_COMPRO_VIDEOMATE: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* TODO: someone can do some cleanup here... + not everything's needed */ + em28xx_write_regs(dev, 0x04, "\x00", 1); + msleep(10); + em28xx_write_regs(dev, 0x04, "\x01", 1); + msleep(10); + em28xx_write_regs(dev, 0x08, "\xfd", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xfc", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xdc", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xfc", 1); + mdelay(70); + break; + + case EM2870_BOARD_TERRATEC_XS_MT2060: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* this device needs some gpio writes to get the DVB-T + demod work */ + em28xx_write_regs(dev, 0x08, "\xfe", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xde", 1); + mdelay(70); + dev->em28xx_write_regs(dev, 0x08, "\xfe", 1); + mdelay(70); + break; + + case EM2870_BOARD_PINNACLE_PCTV_DVB: + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* this device needs some gpio writes to get the + DVB-T demod work */ + em28xx_write_regs(dev, 0x08, "\xfe", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xde", 1); + mdelay(70); + em28xx_write_regs(dev, 0x08, "\xfe", 1); + mdelay(70); + /* switch em2880 rc protocol */ + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x22", 1); + /* should be added ir_codes here */ + break; + case EM2820_BOARD_GADMEI_UTV310: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* Turn on analog audio output */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); + break; + + case EM2860_BOARD_GADMEI_UTV330: + /* Turn on IR */ + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x07", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* should be added ir_codes here */ + break; + + case EM2820_BOARD_MSI_VOX_USB_2: + em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1); + em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1); + /* enables audio for that device */ + em28xx_write_regs_req(dev, 0x00, 0x08, "\xfd", 1); break; } @@ -640,12 +1549,16 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl) case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: ctl->demod = XC3028_FE_ZARLINK456; break; + case EM2880_BOARD_TERRATEC_HYBRID_XS: + ctl->demod = XC3028_FE_ZARLINK456; + break; case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: /* djh - Not sure which demod we need here */ ctl->demod = XC3028_FE_DEFAULT; break; - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: + case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: /* FIXME: Better to specify the needed IF */ ctl->demod = XC3028_FE_DEFAULT; break; @@ -810,6 +1723,8 @@ void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir) break; case (EM2800_BOARD_KWORLD_USB2800): break; + case (EM2800_BOARD_GRABBEEX_USB2800): + break; } } @@ -824,7 +1739,7 @@ void em28xx_card_setup(struct em28xx *dev) case EM2820_BOARD_HAUPPAUGE_WINTV_USB_2: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900: case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: { struct tveeprom tv; #ifdef CONFIG_MODULES @@ -837,7 +1752,7 @@ void em28xx_card_setup(struct em28xx *dev) dev->tuner_type = tv.tuner_type; - if (tv.audio_processor == AUDIO_CHIP_MSP34XX) { + if (tv.audio_processor == V4L2_IDENT_MSPX4XX) { dev->i2s_speed = 2048000; dev->has_msp34xx = 1; } @@ -855,11 +1770,21 @@ void em28xx_card_setup(struct em28xx *dev) case EM2800_BOARD_UNKNOWN: if (!em28xx_hint_board(dev)) em28xx_set_model(dev); + break; } if (dev->has_snapshot_button) em28xx_register_snapshot_button(dev); + if (dev->valid == EM28XX_BOARD_NOT_VALIDATED) { + em28xx_errdev("\n\n"); + em28xx_errdev("The support for this board weren't " + "valid yet.\n"); + em28xx_errdev("Please send a report of having this working\n"); + em28xx_errdev("not to V4L mailing list (and/or to other " + "addresses)\n\n"); + } + /* Allow override tuner type by a module parameter */ if (tuner >= 0) dev->tuner_type = tuner; diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c index adf2a6552..5b532ccec 100644 --- a/linux/drivers/media/video/em28xx/em28xx-dvb.c +++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c @@ -6,6 +6,7 @@ (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com> - Fixes for the driver to properly work with HVR-950 - Fixes for the driver to properly work with Pinnacle PCTV HD Pro Stick + - Fixes for the driver to properly work with AMD ATI TV Wonder HD 600 (c) 2008 Aidan Thornton <makosoft@googlemail.com> @@ -410,8 +411,9 @@ static int dvb_init(struct em28xx *dev) em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); /* init frontend */ switch (dev->model) { - case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950: + case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950: case EM2880_BOARD_PINNACLE_PCTV_HD_PRO: + case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600: dvb->frontend = dvb_attach(lgdt330x_attach, &em2880_lgdt3303_dev, &dev->i2c_adap); @@ -442,6 +444,15 @@ static int dvb_init(struct em28xx *dev) } break; #endif + case EM2880_BOARD_TERRATEC_HYBRID_XS: + dvb->frontend = dvb_attach(zl10353_attach, + &em28xx_zl10353_with_xc3028, + &dev->i2c_adap); + if (attach_xc3028(0x61, dev) < 0) { + result = -EINVAL; + goto out_free; + } + break; default: printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card" " isn't supported yet\n", diff --git a/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c index c456f9945..c9a2d4808 100644 --- a/linux/drivers/media/video/em28xx/em28xx-video.c +++ b/linux/drivers/media/video/em28xx/em28xx-video.c @@ -1555,6 +1555,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) struct em28xx_fh *fh; enum v4l2_buf_type fh_type = 0; + lock_kernel(); list_for_each_entry(h, &em28xx_devlist, devlist) { if (h->vdev->minor == minor) { dev = h; @@ -1570,8 +1571,10 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) dev = h; } } - if (NULL == dev) + if (NULL == dev) { + unlock_kernel(); return -ENODEV; + } em28xx_videodbg("open minor=%d type=%s users=%d\n", minor, v4l2_type_names[fh_type], dev->users); @@ -1587,6 +1590,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL); if (!fh) { em28xx_errdev("em28xx-video.c: Out of memory?!\n"); + unlock_kernel(); return -ENOMEM; } mutex_lock(&dev->lock); @@ -1630,6 +1634,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp) sizeof(struct em28xx_buffer), fh); mutex_unlock(&dev->lock); + unlock_kernel(); return errCode; } @@ -1821,20 +1826,7 @@ static const struct file_operations em28xx_v4l_fops = { .compat_ioctl = v4l_compat_ioctl32, }; -static const struct file_operations radio_fops = { - .owner = THIS_MODULE, - .open = em28xx_v4l2_open, - .release = em28xx_v4l2_close, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; - -static const struct video_device em28xx_video_template = { - .fops = &em28xx_v4l_fops, - .release = video_device_release, - - .minor = -1, +static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1877,16 +1869,29 @@ static const struct video_device em28xx_video_template = { #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif +}; + +static const struct video_device em28xx_video_template = { + .fops = &em28xx_v4l_fops, + .release = video_device_release, + .ioctl_ops = &video_ioctl_ops, + + .minor = -1, .tvnorms = V4L2_STD_ALL, .current_norm = V4L2_STD_PAL, }; -static struct video_device em28xx_radio_template = { - .name = "em28xx-radio", - .type = VID_TYPE_TUNER, - .fops = &radio_fops, - .minor = -1, +static const struct file_operations radio_fops = { + .owner = THIS_MODULE, + .open = em28xx_v4l2_open, + .release = em28xx_v4l2_close, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .llseek = no_llseek, +}; + +static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = radio_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, @@ -1905,6 +1910,13 @@ static struct video_device em28xx_radio_template = { #endif }; +static struct video_device em28xx_radio_template = { + .name = "em28xx-radio", + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, + .minor = -1, +}; + /******************************** usb interface ******************************/ @@ -1945,7 +1957,6 @@ EXPORT_SYMBOL(em28xx_unregister_extension); static struct video_device *em28xx_vdev_init(struct em28xx *dev, const struct video_device *template, - const int type, const char *type_name) { struct video_device *vfd; @@ -1957,7 +1968,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, vfd->minor = -1; vfd->parent = &dev->udev->dev; vfd->release = video_device_release; - vfd->type = type; vfd->debug = video_debug; snprintf(vfd->name, sizeof(vfd->name), "%s %s", @@ -2035,14 +2045,11 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, list_add_tail(&dev->devlist, &em28xx_devlist); /* allocate and fill video video_device struct */ - dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, - VID_TYPE_CAPTURE, "video"); + dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video"); if (NULL == dev->vdev) { em28xx_errdev("cannot allocate video_device.\n"); goto fail_unreg; } - if (dev->tuner_type != TUNER_ABSENT) - dev->vdev->type |= VID_TYPE_TUNER; /* register v4l2 video video_device */ retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, @@ -2054,8 +2061,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, } /* Allocate and fill vbi video_device struct */ - dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, - VFL_TYPE_VBI, "vbi"); + dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template, "vbi"); /* register v4l2 vbi video_device */ if (video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]) < 0) { @@ -2065,8 +2071,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev, } if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) { - dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, - VFL_TYPE_RADIO, "radio"); + dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template, "radio"); if (NULL == dev->radio_dev) { em28xx_errdev("cannot allocate video_device.\n"); goto fail_unreg; diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index 6db96db0f..e5e47fe66 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -55,15 +55,58 @@ #define EM2880_BOARD_TERRATEC_PRODIGY_XS 13 #define EM2820_BOARD_PROLINK_PLAYTV_USB2 14 #define EM2800_BOARD_VGEAR_POCKETTV 15 -#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16 +#define EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950 16 #define EM2880_BOARD_PINNACLE_PCTV_HD_PRO 17 #define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2 18 #define EM2860_BOARD_POINTNIX_INTRAORAL_CAMERA 19 +#define EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600 20 +#define EM2800_BOARD_GRABBEEX_USB2800 21 +#define EM2750_BOARD_UNKNOWN 22 +#define EM2750_BOARD_DLCW_130 23 +#define EM2820_BOARD_DLINK_USB_TV 24 +#define EM2820_BOARD_GADMEI_UTV310 25 +#define EM2820_BOARD_HERCULES_SMART_TV_USB2 26 +#define EM2820_BOARD_PINNACLE_USB_2_FM1216ME 27 +#define EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE 28 +#define EM2820_BOARD_PINNACLE_DVC_100 29 +#define EM2820_BOARD_VIDEOLOGY_20K14XUSB 30 +#define EM2821_BOARD_USBGEAR_VD204 31 +#define EM2821_BOARD_SUPERCOMP_USB_2 32 +#define EM2821_BOARD_PROLINK_PLAYTV_USB2 33 +#define EM2860_BOARD_TERRATEC_HYBRID_XS 34 +#define EM2860_BOARD_TYPHOON_DVD_MAKER 35 +#define EM2860_BOARD_NETGMBH_CAM 36 +#define EM2860_BOARD_GADMEI_UTV330 37 +#define EM2861_BOARD_YAKUMO_MOVIE_MIXER 38 +#define EM2861_BOARD_KWORLD_PVRTV_300U 39 +#define EM2861_BOARD_PLEXTOR_PX_TV100U 40 +#define EM2870_BOARD_KWORLD_350U 41 +#define EM2870_BOARD_KWORLD_355U 42 +#define EM2870_BOARD_TERRATEC_XS 43 +#define EM2870_BOARD_TERRATEC_XS_MT2060 44 +#define EM2870_BOARD_PINNACLE_PCTV_DVB 45 +#define EM2870_BOARD_COMPRO_VIDEOMATE 46 +#define EM2880_BOARD_KWORLD_DVB_305U 47 +#define EM2880_BOARD_KWORLD_DVB_310U 48 +#define EM2880_BOARD_MSI_DIGIVOX_AD 49 +#define EM2880_BOARD_MSI_DIGIVOX_AD_II 50 +#define EM2880_BOARD_TERRATEC_HYBRID_XS_FR 51 +#define EM2881_BOARD_DNT_DA2_HYBRID 52 +#define EM2881_BOARD_PINNACLE_HYBRID_PRO 53 +#define EM2882_BOARD_KWORLD_VS_DVBT 54 +#define EM2882_BOARD_TERRATEC_HYBRID_XS 55 +#define EM2882_BOARD_PINNACLE_HYBRID_PRO 56 +#define EM2883_BOARD_KWORLD_HYBRID_A316 57 +#define EM2820_BOARD_COMPRO_VIDEOMATE_FORYOU 58 /* Limits minimum and default number of buffers */ #define EM28XX_MIN_BUF 4 #define EM28XX_DEF_BUF 8 +/* Params for validated field */ +#define EM28XX_BOARD_NOT_VALIDATED 1 +#define EM28XX_BOARD_VALIDATED 0 + /* maximum number of em28xx boards */ #define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */ @@ -252,6 +295,7 @@ struct em28xx_board { unsigned int max_range_640_480:1; unsigned int has_dvb:1; unsigned int has_snapshot_button:1; + unsigned int valid:1; enum em28xx_decoder decoder; @@ -340,6 +384,7 @@ struct em28xx { unsigned int max_range_640_480:1; unsigned int has_dvb:1; unsigned int has_snapshot_button:1; + unsigned int valid:1; /* report for validated boards */ /* Some older em28xx chips needs a waiting time after writing */ unsigned int wait_after_write; @@ -369,7 +414,7 @@ struct em28xx { v4l2_std_id norm; /* selected tv norm */ int ctl_freq; /* selected frequency */ unsigned int ctl_input; /* selected input */ - unsigned int ctl_ainput; /* slected audio input */ + unsigned int ctl_ainput;/* selected audio input */ int mute; int volume; /* frame properties */ diff --git a/linux/drivers/media/video/et61x251/et61x251_core.c b/linux/drivers/media/video/et61x251/et61x251_core.c index 0711a34fb..7d0f31db5 100644 --- a/linux/drivers/media/video/et61x251/et61x251_core.c +++ b/linux/drivers/media/video/et61x251/et61x251_core.c @@ -2589,8 +2589,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, "ET61X[12]51 PC Camera"); - cam->v4ldev->owner = THIS_MODULE; - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &et61x251_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c index 18c1dec2f..739ef557c 100644 --- a/linux/drivers/media/video/gspca/conex.c +++ b/linux/drivers/media/video/gspca/conex.c @@ -123,7 +123,7 @@ static void reg_r(struct gspca_dev *gspca_dev, { struct usb_device *dev = gspca_dev->dev; -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG if (len > sizeof gspca_dev->usb_buf) { err("reg_r: buffer overflow"); return; @@ -163,7 +163,7 @@ static void reg_w(struct gspca_dev *gspca_dev, { struct usb_device *dev = gspca_dev->dev; -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG if (len > sizeof gspca_dev->usb_buf) { err("reg_w: buffer overflow"); return; @@ -815,7 +815,6 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam; cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; @@ -1008,9 +1007,8 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x0572, 0x0041), DVNM("Creative Notebook cx11646")}, + {USB_DEVICE(0x0572, 0x0041)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -1028,6 +1026,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/etoms.c b/linux/drivers/media/video/gspca/etoms.c index 3d420ea65..626d03e17 100644 --- a/linux/drivers/media/video/gspca/etoms.c +++ b/linux/drivers/media/video/gspca/etoms.c @@ -233,7 +233,7 @@ static void reg_r(struct gspca_dev *gspca_dev, { struct usb_device *dev = gspca_dev->dev; -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG if (len > sizeof gspca_dev->usb_buf) { err("reg_r: buffer overflow"); return; @@ -271,7 +271,7 @@ static void reg_w(struct gspca_dev *gspca_dev, { struct usb_device *dev = gspca_dev->dev; -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG if (len > sizeof gspca_dev->usb_buf) { err("reg_w: buffer overflow"); return; @@ -461,6 +461,52 @@ static void Et_init2(struct gspca_dev *gspca_dev) reg_w_val(gspca_dev, 0x80, 0x20); /* 0x20; */ } +static void setbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + __u8 brightness = sd->brightness; + + for (i = 0; i < 4; i++) + reg_w_val(gspca_dev, ET_O_RED + i, brightness); +} + +static void getbrightness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + int brightness = 0; + + for (i = 0; i < 4; i++) { + reg_r(gspca_dev, ET_O_RED + i, 1); + brightness += gspca_dev->usb_buf[0]; + } + sd->brightness = brightness >> 3; +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 }; + __u8 contrast = sd->contrast; + + memset(RGBG, contrast, sizeof(RGBG) - 2); + reg_w(gspca_dev, ET_G_RED, RGBG, 6); +} + +static void getcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + int contrast = 0; + + for (i = 0; i < 4; i++) { + reg_r(gspca_dev, ET_G_RED + i, 1); + contrast += gspca_dev->usb_buf[0]; + } + sd->contrast = contrast >> 2; +} + static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -492,6 +538,16 @@ static void getcolors(struct gspca_dev *gspca_dev) } } +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->autogain) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; +} + static void Et_init1(struct gspca_dev *gspca_dev) { __u8 value; @@ -599,26 +655,10 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 vendor; - __u16 product; - - vendor = id->idVendor; - product = id->idProduct; -/* switch (vendor) { */ -/* case 0x102c: * Etoms */ - switch (product) { - case 0x6151: - sd->sensor = SENSOR_PAS106; /* Etoms61x151 */ - break; - case 0x6251: - sd->sensor = SENSOR_TAS5130CXX; /* Etoms61x251 */ - break; -/* } */ -/* break; */ - } + cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 1; + sd->sensor = id->driver_info; if (sd->sensor == SENSOR_PAS106) { cam->cam_mode = sif_mode; cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; @@ -630,6 +670,7 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->contrast = CONTRAST_DEF; sd->colors = COLOR_DEF; sd->autogain = AUTOGAIN_DEF; + sd->ag_cnt = -1; return 0; } @@ -657,6 +698,8 @@ static void sd_start(struct gspca_dev *gspca_dev) else Et_init2(gspca_dev); + setautogain(gspca_dev); + reg_w_val(gspca_dev, ET_RESET_ALL, 0x08); et_video(gspca_dev, 1); /* video on */ } @@ -674,52 +717,6 @@ static void sd_close(struct gspca_dev *gspca_dev) { } -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - __u8 brightness = sd->brightness; - - for (i = 0; i < 4; i++) - reg_w_val(gspca_dev, ET_O_RED + i, brightness); -} - -static void getbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - int brightness = 0; - - for (i = 0; i < 4; i++) { - reg_r(gspca_dev, ET_O_RED + i, 1); - brightness += gspca_dev->usb_buf[0]; - } - sd->brightness = brightness >> 3; -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 RGBG[] = { 0x80, 0x80, 0x80, 0x80, 0x00, 0x00 }; - __u8 contrast = sd->contrast; - - memset(RGBG, contrast, sizeof(RGBG) - 2); - reg_w(gspca_dev, ET_G_RED, RGBG, 6); -} - -static void getcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - int contrast = 0; - - for (i = 0; i < 4; i++) { - reg_r(gspca_dev, ET_G_RED + i, 1); - contrast += gspca_dev->usb_buf[0]; - } - sd->contrast = contrast >> 2; -} - static __u8 Et_getgainG(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -755,15 +752,22 @@ static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain) #define LIMIT(color) \ (unsigned char)((color > 0xff)?0xff:((color < 0)?0:color)) -static void setautogain(struct gspca_dev *gspca_dev) +static void do_autogain(struct gspca_dev *gspca_dev) { - __u8 luma = 0; + struct sd *sd = (struct sd *) gspca_dev; + __u8 luma; __u8 luma_mean = 128; __u8 luma_delta = 20; __u8 spring = 4; - int Gbright = 0; + int Gbright; __u8 r, g, b; + if (sd->ag_cnt < 0) + return; + if (--sd->ag_cnt >= 0) + return; + sd->ag_cnt = AG_CNT_START; + Gbright = Et_getgainG(gspca_dev); reg_r(gspca_dev, ET_LUMA_CENTER, 4); g = (gspca_dev->usb_buf[0] + gspca_dev->usb_buf[3]) >> 1; @@ -790,7 +794,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, __u8 *data, /* isoc packet */ int len) /* iso packet length */ { - struct sd *sd; int seqframe; seqframe = data[0] & 0x3f; @@ -805,13 +808,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0); gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); - sd = (struct sd *) gspca_dev; - if (sd->ag_cnt >= 0) { - if (--sd->ag_cnt < 0) { - sd->ag_cnt = AG_CNT_START; - setautogain(gspca_dev); - } - } return; } if (len) { @@ -884,10 +880,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->autogain = val; - if (val) - sd->ag_cnt = AG_CNT_START; - else - sd->ag_cnt = -1; + if (gspca_dev->streaming) + setautogain(gspca_dev); return 0; } @@ -911,15 +905,15 @@ static struct sd_desc sd_desc = { .stop0 = sd_stop0, .close = sd_close, .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, #ifndef CONFIG_USB_ET61X251 - {USB_DEVICE(0x102c, 0x6151), DVNM("Qcam Sangha CIF")}, + {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, #endif - {USB_DEVICE(0x102c, 0x6251), DVNM("Qcam xxxxxx VGA")}, {} }; @@ -938,6 +932,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c index 729e0b4ed..df7c5cb0a 100644 --- a/linux/drivers/media/video/gspca/gspca.c +++ b/linux/drivers/media/video/gspca/gspca.c @@ -51,7 +51,7 @@ MODULE_LICENSE("GPL"); static int video_nr = -1; -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG int gspca_debug = D_ERR | D_PROBE; EXPORT_SYMBOL(gspca_debug); @@ -118,7 +118,8 @@ static void fill_frame(struct gspca_dev *gspca_dev, cam_pkt_op pkt_scan; if (urb->status != 0) { - PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); + if (!gspca_dev->frozen) + PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); return; /* disconnection ? */ } pkt_scan = gspca_dev->sd_desc->pkt_scan; @@ -684,7 +685,7 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, w = fmt->fmt.pix.width; h = fmt->fmt.pix.height; -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG if (gspca_debug & D_CONF) PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h); #endif @@ -792,7 +793,7 @@ static int dev_open(struct inode *inode, struct file *file) } gspca_dev->users++; file->private_data = gspca_dev; -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG /* activate the v4l2 debug */ if (gspca_debug & D_V4L2) gspca_dev->vdev.debug |= 3; @@ -841,13 +842,24 @@ static int vidioc_querycap(struct file *file, void *priv, memset(cap, 0, sizeof *cap); strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver); - strncpy(cap->card, gspca_dev->cam.dev_name, sizeof cap->card); +/* strncpy(cap->card, gspca_dev->cam.dev_name, sizeof cap->card); */ + if (gspca_dev->dev->product != NULL) { + strncpy(cap->card, gspca_dev->dev->product, + sizeof cap->card); + } else { + snprintf(cap->card, sizeof cap->card, + "USB Camera (%04x:%04x)", + le16_to_cpu(gspca_dev->dev->descriptor.idVendor), + le16_to_cpu(gspca_dev->dev->descriptor.idProduct)); + } strncpy(cap->bus_info, gspca_dev->dev->bus->bus_name, sizeof cap->bus_info); cap->version = DRIVER_VERSION_NUMBER; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (gspca_dev->flags & GSPCA_SENSOR_UPSIDE_DOWN_FLAG) + cap->capabilities |= V4L2_CAP_SENSOR_UPSIDE_DOWN; return 0; } @@ -881,11 +893,6 @@ static int vidioc_queryctrl(struct file *file, void *priv, return 0; } } - if (id >= V4L2_CID_BASE - && id <= V4L2_CID_LASTP1) { - q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; - } return -EINVAL; } @@ -902,7 +909,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, if (ctrl->id != ctrls->qctrl.id) continue; if (ctrl->value < ctrls->qctrl.minimum - && ctrl->value > ctrls->qctrl.maximum) + || ctrl->value > ctrls->qctrl.maximum) return -ERANGE; PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); if (mutex_lock_interruptible(&gspca_dev->usb_lock)) @@ -1078,7 +1085,7 @@ static int vidioc_streamon(struct file *file, void *priv, if (ret < 0) goto out; } -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG if (gspca_debug & D_STREAM) { PDEBUG_MODE("stream on OK", gspca_dev->pixfmt, @@ -1658,12 +1665,7 @@ static struct file_operations dev_fops = { .poll = dev_poll, }; -static struct video_device gspca_template = { - .name = "gspca main driver", - .type = VID_TYPE_CAPTURE, - .fops = &dev_fops, - .release = dev_release, /* mandatory */ - .minor = -1, +static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_qbuf = vidioc_qbuf, @@ -1692,6 +1694,14 @@ static struct video_device gspca_template = { #endif }; +static struct video_device gspca_template = { + .name = "gspca main driver", + .fops = &dev_fops, + .ioctl_ops = &dev_ioctl_ops, + .release = dev_release, /* mandatory */ + .minor = -1, +}; + /* * probe and create a new gspca device * @@ -1753,6 +1763,7 @@ int gspca_dev_probe(struct usb_interface *intf, memcpy(&gspca_dev->fops, &dev_fops, sizeof gspca_dev->fops); gspca_dev->vdev.fops = &gspca_dev->fops; gspca_dev->fops.owner = module; /* module protection */ + gspca_dev->present = 1; ret = video_register_device(&gspca_dev->vdev, VFL_TYPE_GRABBER, video_nr); @@ -1761,7 +1772,6 @@ int gspca_dev_probe(struct usb_interface *intf, goto out; } - gspca_dev->present = 1; usb_set_intfdata(intf, gspca_dev); PDEBUG(D_PROBE, "probe ok"); return 0; @@ -1803,6 +1813,33 @@ void gspca_disconnect(struct usb_interface *intf) } EXPORT_SYMBOL(gspca_disconnect); +#ifdef CONFIG_PM +int gspca_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + + if (!gspca_dev->streaming) + return 0; + gspca_dev->frozen = 1; /* avoid urb error messages */ + gspca_dev->sd_desc->stopN(gspca_dev); + destroy_urbs(gspca_dev); + gspca_set_alt0(gspca_dev); + gspca_dev->sd_desc->stop0(gspca_dev); + return 0; +} +EXPORT_SYMBOL(gspca_suspend); + +int gspca_resume(struct usb_interface *intf) +{ + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + + gspca_dev->frozen = 0; + if (!gspca_dev->streaming) + return 0; + return gspca_init_transfer(gspca_dev); +} +EXPORT_SYMBOL(gspca_resume); +#endif /* -- cam driver utility functions -- */ /* auto gain and exposure algorithm based on the knee algorithm described here: @@ -1908,7 +1945,7 @@ static void __exit gspca_exit(void) module_init(gspca_init); module_exit(gspca_exit); -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG module_param_named(debug, gspca_debug, int, 0644); MODULE_PARM_DESC(debug, "Debug (bit) 0x01:error 0x02:probe 0x04:config" diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h index 3fd2c4eee..1920c99d6 100644 --- a/linux/drivers/media/video/gspca/gspca.h +++ b/linux/drivers/media/video/gspca/gspca.h @@ -9,7 +9,10 @@ #include <media/v4l2-common.h> #include <linux/mutex.h> -#ifdef CONFIG_VIDEO_ADV_DEBUG +/* compilation option */ +#define GSPCA_DEBUG 1 + +#ifdef GSPCA_DEBUG /* GSPCA our debug messages */ extern int gspca_debug; #define PDEBUG(level, fmt, args...) \ @@ -53,7 +56,6 @@ extern int gspca_debug; /* device information - set at probe time */ struct cam { - char *dev_name; struct v4l2_pix_format *cam_mode; /* size nmodes */ char nmodes; __u8 epaddr; @@ -116,6 +118,9 @@ struct gspca_frame { struct v4l2_buffer v4l2_buf; }; +/* defines for the flags member */ +#define GSPCA_SENSOR_UPSIDE_DOWN_FLAG 0x01 + struct gspca_dev { struct video_device vdev; /* !! must be the first item */ struct file_operations fops; @@ -152,12 +157,16 @@ struct gspca_dev { struct mutex queue_lock; /* ISOC queue protection */ __u32 sequence; /* frame sequence number */ char streaming; +#ifdef CONFIG_PM + char frozen; /* suspend - resume */ +#endif char users; /* number of opens */ char present; /* device connected */ char nbufread; /* number of buffers for read() */ char nurbs; /* number of allocated URBs */ char memory; /* memory type (V4L2_MEMORY_xxx) */ __u8 nbalt; /* number of USB alternate settings */ + __u8 flags; /* see GSPCA_XXX_FLAG defines */ }; int gspca_dev_probe(struct usb_interface *intf, @@ -171,6 +180,10 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev, struct gspca_frame *frame, const __u8 *data, int len); +#ifdef CONFIG_PM +int gspca_suspend(struct usb_interface *intf, pm_message_t message); +int gspca_resume(struct usb_interface *intf); +#endif int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee); #endif /* GSPCAV2_H */ diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c index a4706162f..d7e209578 100644 --- a/linux/drivers/media/video/gspca/mars.c +++ b/linux/drivers/media/video/gspca/mars.c @@ -137,7 +137,6 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam; cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; @@ -421,9 +420,8 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x093a, 0x050f), DVNM("Mars-Semi Pc-Camera")}, + {USB_DEVICE(0x093a, 0x050f)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -441,6 +439,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/ov519.c b/linux/drivers/media/video/gspca/ov519.c index 1fb3a3eee..e1c665b4d 100644 --- a/linux/drivers/media/video/gspca/ov519.c +++ b/linux/drivers/media/video/gspca/ov519.c @@ -40,14 +40,15 @@ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ /* Determined by sensor type */ - short maxwidth; - short maxheight; + char sif; unsigned char primary_i2c_slave; /* I2C write id of sensor */ unsigned char brightness; unsigned char contrast; unsigned char colors; + __u8 hflip; + __u8 vflip; char compress; /* Should the next frame be compressed? */ char compress_inited; /* Are compression params uploaded? */ @@ -77,9 +78,12 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 { { .id = V4L2_CID_BRIGHTNESS, @@ -88,12 +92,12 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 255, .step = 1, - .default_value = 127, +#define BRIGHTNESS_DEF 127 + .default_value = BRIGHTNESS_DEF, }, .set = sd_setbrightness, .get = sd_getbrightness, }, -#define SD_CONTRAST 1 { { .id = V4L2_CID_CONTRAST, @@ -102,31 +106,61 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 255, .step = 1, - .default_value = 127, +#define CONTRAST_DEF 127 + .default_value = CONTRAST_DEF, }, .set = sd_setcontrast, .get = sd_getcontrast, }, -#define SD_COLOR 2 { { .id = V4L2_CID_SATURATION, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", + .name = "Color", .minimum = 0, .maximum = 255, .step = 1, - .default_value = 127, +#define COLOR_DEF 127 + .default_value = COLOR_DEF, }, .set = sd_setcolors, .get = sd_getcolors, }, +/* next controls work with ov7670 only */ + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, +#define HFLIP_DEF 0 + .default_value = HFLIP_DEF, + }, + .set = sd_sethflip, + .get = sd_gethflip, + }, + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vflip", + .minimum = 0, + .maximum = 1, + .step = 1, +#define VFLIP_DEF 0 + .default_value = VFLIP_DEF, + }, + .set = sd_setvflip, + .get = sd_getvflip, + }, }; static struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, - .sizeimage = 320 * 240 * 3 / 8 + 589, + .sizeimage = 320 * 240 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 1}, {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, @@ -138,12 +172,12 @@ static struct v4l2_pix_format vga_mode[] = { static struct v4l2_pix_format sif_mode[] = { {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 176, - .sizeimage = 176 * 144 * 3 / 8 + 589, + .sizeimage = 176 * 144 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 1}, {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 352, - .sizeimage = 352 * 288 * 3 / 8 + 589, + .sizeimage = 352 * 288 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 0}, }; @@ -225,6 +259,7 @@ static struct v4l2_pix_format sif_mode[] = { #define OV7670_REG_VSTART 0x19 /* Vert start high bits */ #define OV7670_REG_VSTOP 0x1a /* Vert stop high bits */ #define OV7670_REG_MVFP 0x1e /* Mirror / vflip */ +#define OV7670_MVFP_VFLIP 0x10 /* vertical flip */ #define OV7670_MVFP_MIRROR 0x20 /* Mirror image */ #define OV7670_REG_AEW 0x24 /* AGC upper limit */ #define OV7670_REG_AEB 0x25 /* AGC lower limit */ @@ -258,16 +293,6 @@ static struct v4l2_pix_format sif_mode[] = { #define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */ #define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */ -struct ovsensor_window { - short x; - short y; - short width; - short height; -/* int format; */ - short quarter; /* Scale width and height down 2x */ - short clockdiv; /* Clock divisor setting */ -}; - static unsigned char ov7670_abs_to_sm(unsigned char v) { if (v > 127) @@ -499,19 +524,6 @@ static int init_ov_sensor(struct sd *sd) return 0; } -/* Switch on standard JPEG compression. Returns 0 for success. */ -static int ov519_init_compression(struct sd *sd) -{ - if (!sd->compress_inited) { - if (reg_w_mask(sd, OV519_SYS_EN_CLK1, 1 << 2, 1 << 2) < 0) { - PDEBUG(D_ERR, "Error switching to compressed mode"); - return -EIO; - } - sd->compress_inited = 1; - } - return 0; -} - /* Set the read and write slave IDs. The "slave" argument is the write slave, * and the read slave will be set to (slave + 1). * This should not be called from outside the i2c I/O functions. @@ -681,21 +693,17 @@ static int ov8xx0_configure(struct sd *sd) return -1; } if ((rc & 3) == 1) { - PDEBUG(D_PROBE, "Sensor is an OV8610"); sd->sensor = SEN_OV8610; } else { PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3); return -1; } PDEBUG(D_PROBE, "Writing 8610 registers"); - if (write_i2c_regvals(sd, - norm_8610, - sizeof norm_8610 / sizeof norm_8610[0])) + if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610))) return -1; /* Set sensor-specific vars */ - sd->maxwidth = 640; - sd->maxheight = 480; +/* sd->sif = 0; already done */ return 0; } @@ -825,7 +833,7 @@ static int ov7xx0_configure(struct sd *sd) { OV7670_REG_COM7, OV7670_COM7_RESET }, { OV7670_REG_TSLB, 0x04 }, /* OV */ { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ - { OV7670_REG_CLKRC, 0x1 }, + { OV7670_REG_CLKRC, 0x01 }, /* * Set the hardware window. These values from OV don't entirely * make sense - hstop is less than hstart. But they work... @@ -839,16 +847,12 @@ static int ov7xx0_configure(struct sd *sd) { 0x70, 0x3a }, { 0x71, 0x35 }, { 0x72, 0x11 }, { 0x73, 0xf0 }, { 0xa2, 0x02 }, -/* jfm */ -/* { OV7670_REG_COM10, 0x0 }, */ +/* { OV7670_REG_COM10, 0x0 }, */ /* Gamma curve values */ { 0x7a, 0x20 }, -/* jfm:win 7b=1c */ { 0x7b, 0x10 }, -/* jfm:win 7c=28 */ { 0x7c, 0x1e }, -/* jfm:win 7d=3c */ { 0x7d, 0x35 }, { 0x7e, 0x5a }, { 0x7f, 0x69 }, { 0x80, 0x76 }, { 0x81, 0x80 }, @@ -864,13 +868,11 @@ static int ov7xx0_configure(struct sd *sd) | OV7670_COM8_BFILT }, { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 }, { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ -/* jfm:win 14=38 */ { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */ { OV7670_REG_BD50MAX, 0x05 }, { OV7670_REG_BD60MAX, 0x07 }, { OV7670_REG_AEW, 0x95 }, { OV7670_REG_AEB, 0x33 }, { OV7670_REG_VPT, 0xe3 }, { OV7670_REG_HAECC1, 0x78 }, { OV7670_REG_HAECC2, 0x68 }, -/* jfm:win a1=0b */ { 0xa1, 0x03 }, /* magic */ { OV7670_REG_HAECC3, 0xd8 }, { OV7670_REG_HAECC4, 0xd8 }, { OV7670_REG_HAECC5, 0xf0 }, { OV7670_REG_HAECC6, 0x90 }, @@ -884,8 +886,6 @@ static int ov7xx0_configure(struct sd *sd) /* Almost all of these are magic "reserved" values. */ { OV7670_REG_COM5, 0x61 }, { OV7670_REG_COM6, 0x4b }, { 0x16, 0x02 }, -/* jfm */ -/* { OV7670_REG_MVFP, 0x07|OV7670_MVFP_MIRROR }, */ { OV7670_REG_MVFP, 0x07 }, { 0x21, 0x02 }, { 0x22, 0x91 }, { 0x29, 0x07 }, { 0x33, 0x0b }, @@ -930,7 +930,10 @@ static int ov7xx0_configure(struct sd *sd) { OV7670_REG_EDGE, 0 }, { 0x75, 0x05 }, { 0x76, 0xe1 }, { 0x4c, 0 }, { 0x77, 0x01 }, - { OV7670_REG_COM13, 0xc3 }, { 0x4b, 0x09 }, + { OV7670_REG_COM13, OV7670_COM13_GAMMA + | OV7670_COM13_UVSAT + | 2}, /* was 3 */ + { 0x4b, 0x09 }, { 0xc9, 0x60 }, { OV7670_REG_COM16, 0x38 }, { 0x56, 0x40 }, @@ -956,30 +959,10 @@ static int ov7xx0_configure(struct sd *sd) { 0x79, 0x03 }, { 0xc8, 0x40 }, { 0x79, 0x05 }, { 0xc8, 0x30 }, { 0x79, 0x26 }, - - /* Format YUV422 */ - { OV7670_REG_COM7, OV7670_COM7_YUV }, /* Selects YUV mode */ - { OV7670_REG_RGB444, 0 }, /* No RGB444 please */ - { OV7670_REG_COM1, 0 }, - { OV7670_REG_COM15, OV7670_COM15_R00FF }, - { OV7670_REG_COM9, 0x18 }, - /* 4x gain ceiling; 0x8 is reserved bit */ - { 0x4f, 0x80 }, /* "matrix coefficient 1" */ - { 0x50, 0x80 }, /* "matrix coefficient 2" */ - { 0x52, 0x22 }, /* "matrix coefficient 4" */ - { 0x53, 0x5e }, /* "matrix coefficient 5" */ - { 0x54, 0x80 }, /* "matrix coefficient 6" */ - { OV7670_REG_COM13, OV7670_COM13_GAMMA|OV7670_COM13_UVSAT }, -}; + }; PDEBUG(D_PROBE, "starting OV7xx0 configuration"); -/* jfm:already done? */ - if (init_ov_sensor(sd) < 0) - PDEBUG(D_ERR, "Failed to read sensor ID"); - else - PDEBUG(D_PROBE, "OV7xx0 initialized"); - /* Detect sensor (sub)type */ rc = i2c_r(sd, OV7610_REG_COM_I); @@ -1025,20 +1008,25 @@ static int ov7xx0_configure(struct sd *sd) return low; } if (high == 0x76) { - if (low == 0x30) { + switch (low) { + case 0x30: PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635"); sd->sensor = SEN_OV7630; - } else if (low == 0x40) { + break; + case 0x40: PDEBUG(D_PROBE, "Sensor is an OV7645"); sd->sensor = SEN_OV7640; /* FIXME */ - } else if (low == 0x45) { + break; + case 0x45: PDEBUG(D_PROBE, "Sensor is an OV7645B"); sd->sensor = SEN_OV7640; /* FIXME */ - } else if (low == 0x48) { + break; + case 0x48: PDEBUG(D_PROBE, "Sensor is an OV7648"); sd->sensor = SEN_OV7640; /* FIXME */ - } else { - PDEBUG(D_PROBE, "Unknown sensor: 0x76%X", low); + break; + default: + PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low); return -1; } } else { @@ -1050,34 +1038,34 @@ static int ov7xx0_configure(struct sd *sd) return -1; } - if (sd->sensor == SEN_OV7620) { + switch (sd->sensor) { + case SEN_OV7620: PDEBUG(D_PROBE, "Writing 7620 registers"); - if (write_i2c_regvals(sd, norm_7620, - sizeof norm_7620 / sizeof norm_7620[0])) + if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620))) return -1; - } else if (sd->sensor == SEN_OV7630) { + break; + case SEN_OV7630: PDEBUG(D_ERR, "7630 is not supported by this driver version"); return -1; - } else if (sd->sensor == SEN_OV7640) { + case SEN_OV7640: PDEBUG(D_PROBE, "Writing 7640 registers"); - if (write_i2c_regvals(sd, norm_7640, - sizeof norm_7640 / sizeof norm_7640[0])) + if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640))) return -1; - } else if (sd->sensor == SEN_OV7670) { + break; + case SEN_OV7670: PDEBUG(D_PROBE, "Writing 7670 registers"); - if (write_i2c_regvals(sd, norm_7670, - sizeof norm_7670 / sizeof norm_7670[0])) + if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670))) return -1; - } else { + break; + default: PDEBUG(D_PROBE, "Writing 7610 registers"); - if (write_i2c_regvals(sd, norm_7610, - sizeof norm_7610 / sizeof norm_7610[0])) + if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610))) return -1; + break; } /* Set sensor-specific vars */ - sd->maxwidth = 640; - sd->maxheight = 480; +/* sd->sif = 0; already done */ return 0; } @@ -1231,43 +1219,45 @@ static int ov6xx0_configure(struct sd *sd) /* Ugh. The first two bits are the version bits, but * the entire register value must be used. I guess OVT * underestimated how many variants they would make. */ - if (rc == 0x00) { + switch (rc) { + case 0x00: sd->sensor = SEN_OV6630; PDEBUG(D_ERR, "WARNING: Sensor is an OV66308. Your camera may have"); PDEBUG(D_ERR, "been misdetected in previous driver versions."); - } else if (rc == 0x01) { + break; + case 0x01: sd->sensor = SEN_OV6620; - PDEBUG(D_PROBE, "Sensor is an OV6620"); - } else if (rc == 0x02) { + break; + case 0x02: sd->sensor = SEN_OV6630; PDEBUG(D_PROBE, "Sensor is an OV66308AE"); - } else if (rc == 0x03) { + break; + case 0x03: sd->sensor = SEN_OV6630; PDEBUG(D_PROBE, "Sensor is an OV66308AF"); - } else if (rc == 0x90) { + break; + case 0x90: sd->sensor = SEN_OV6630; PDEBUG(D_ERR, "WARNING: Sensor is an OV66307. Your camera may have"); PDEBUG(D_ERR, "been misdetected in previous driver versions."); - } else { + break; + default: PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc); return -1; } /* Set sensor-specific vars */ - sd->maxwidth = 352; - sd->maxheight = 288; + sd->sif = 1; if (sd->sensor == SEN_OV6620) { PDEBUG(D_PROBE, "Writing 6x20 registers"); - if (write_i2c_regvals(sd, norm_6x20, - sizeof norm_6x20 / sizeof norm_6x20[0])) + if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20))) return -1; } else { PDEBUG(D_PROBE, "Writing 6x30 registers"); - if (write_i2c_regvals(sd, norm_6x30, - sizeof norm_6x30 / sizeof norm_6x30[0])) + if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30))) return -1; } return 0; @@ -1276,14 +1266,8 @@ static int ov6xx0_configure(struct sd *sd) /* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */ static void ov51x_led_control(struct sd *sd, int on) { - PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); - -/* if (sd->bridge == BRG_OV511PLUS) */ -/* reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0); */ -/* else if (sd->bridge == BRG_OV519) */ - reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */ -/* else if (sd->bclass == BCL_OV518) */ -/* reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02); */ +/* PDEBUG(D_STREAM, "LED (%s)", on ? "on" : "off"); */ + reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */ } /* this function is called at probe time */ @@ -1293,11 +1277,8 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; -/* (from ov519_configure) */ static const struct ov_regvals init_519[] = { { 0x5a, 0x6d }, /* EnableSystem */ -/* jfm trace usbsnoop3-1.txt */ -/* jfm 53 = fb */ { 0x53, 0x9b }, { 0x54, 0xff }, /* set bit2 to enable jpeg */ { 0x5d, 0x03 }, @@ -1314,9 +1295,6 @@ static int sd_config(struct gspca_dev *gspca_dev, if (write_regvals(sd, init_519, ARRAY_SIZE(init_519))) goto error; -/* jfm: not seen in windows trace */ - if (ov519_init_compression(sd)) - goto error; ov51x_led_control(sd, 0); /* turn LED off */ /* Test for 76xx */ @@ -1365,17 +1343,18 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; cam->epaddr = OV511_ENDPOINT_ADDRESS; - if (sd->maxwidth == 640) { + if (!sd->sif) { cam->cam_mode = vga_mode; - cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + cam->nmodes = ARRAY_SIZE(vga_mode); } else { cam->cam_mode = sif_mode; - cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; + cam->nmodes = ARRAY_SIZE(sif_mode); } - cam->dev_name = (char *) id->driver_info; - sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; - sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; - sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value; + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->colors = COLOR_DEF; + sd->hflip = HFLIP_DEF; + sd->vflip = VFLIP_DEF; return 0; error: PDEBUG(D_ERR, "OV519 Config failed"); @@ -1395,8 +1374,7 @@ static int sd_open(struct gspca_dev *gspca_dev) * * Do not put any sensor-specific code in here (including I2C I/O functions) */ -static int ov519_mode_init_regs(struct sd *sd, - int width, int height) +static int ov519_mode_init_regs(struct sd *sd) { static const struct ov_regvals mode_init_519_ov7670[] = { { 0x5d, 0x03 }, /* Turn off suspend mode */ @@ -1442,36 +1420,23 @@ static int ov519_mode_init_regs(struct sd *sd, /* windows reads 0x55 at this point, why? */ }; -/* int hi_res; */ - - PDEBUG(D_CONF, "mode init %dx%d", width, height); - -/* if (width >= 800 && height >= 600) - hi_res = 1; - else - hi_res = 0; */ - -/* if (ov51x_stop(sd) < 0) - return -EIO; */ - /******** Set the mode ********/ if (sd->sensor != SEN_OV7670) { if (write_regvals(sd, mode_init_519, ARRAY_SIZE(mode_init_519))) return -EIO; + if (sd->sensor == SEN_OV7640) { + /* Select 8-bit input mode */ + reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10); + } } else { if (write_regvals(sd, mode_init_519_ov7670, ARRAY_SIZE(mode_init_519_ov7670))) return -EIO; } - if (sd->sensor == SEN_OV7640) { - /* Select 8-bit input mode */ - reg_w_mask(sd, OV519_CAM_DFR, 0x10, 0x10); - } - - reg_w(sd, OV519_CAM_H_SIZE, width >> 4); - reg_w(sd, OV519_CAM_V_SIZE, height >> 3); + reg_w(sd, OV519_CAM_H_SIZE, sd->gspca_dev.width >> 4); + reg_w(sd, OV519_CAM_V_SIZE, sd->gspca_dev.height >> 3); reg_w(sd, OV519_CAM_X_OFFSETL, 0x00); reg_w(sd, OV519_CAM_X_OFFSETH, 0x00); reg_w(sd, OV519_CAM_Y_OFFSETL, 0x00); @@ -1486,9 +1451,10 @@ static int ov519_mode_init_regs(struct sd *sd, /* FIXME: These are only valid at the max resolution. */ sd->clockdiv = 0; - if (sd->sensor == SEN_OV7640) { + switch (sd->sensor) { + case SEN_OV7640: switch (sd->frame_rate) { -/*jfm: default was 30 fps */ +/*fixme: default was 30 fps */ case 30: reg_w(sd, 0xa4, 0x0c); reg_w(sd, 0x23, 0xff); @@ -1518,7 +1484,8 @@ static int ov519_mode_init_regs(struct sd *sd, sd->clockdiv = 1; break; } - } else if (sd->sensor == SEN_OV8610) { + break; + case SEN_OV8610: switch (sd->frame_rate) { default: /* 15 fps */ /* case 15: */ @@ -1534,41 +1501,37 @@ static int ov519_mode_init_regs(struct sd *sd, reg_w(sd, 0x23, 0x1b); break; } - sd->clockdiv = 0; - } else if (sd->sensor == SEN_OV7670) { /* guesses, based on 7640 */ + break; + case SEN_OV7670: /* guesses, based on 7640 */ PDEBUG(D_STREAM, "Setting framerate to %d fps", (sd->frame_rate == 0) ? 15 : sd->frame_rate); + reg_w(sd, 0xa4, 0x10); switch (sd->frame_rate) { case 30: - reg_w(sd, 0xa4, 0x10); reg_w(sd, 0x23, 0xff); break; case 20: - reg_w(sd, 0xa4, 0x10); reg_w(sd, 0x23, 0x1b); break; - default: /* 15 fps */ -/* case 15: */ - reg_w(sd, 0xa4, 0x10); + default: +/* case 15: */ reg_w(sd, 0x23, 0xff); sd->clockdiv = 1; break; } + break; } -/* if (ov51x_restart(sd) < 0) - return -EIO; */ - - /* Reset it just for good measure */ -/* if (ov51x_reset(sd, OV511_RESET_NOREGS) < 0) - return -EIO; */ return 0; } -static int mode_init_ov_sensor_regs(struct sd *sd, - struct ovsensor_window *win) +static int mode_init_ov_sensor_regs(struct sd *sd) { - int qvga = win->quarter; + struct gspca_dev *gspca_dev; + int qvga; + + gspca_dev = &sd->gspca_dev; + qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; /******** Mode (VGA/QVGA) and sensor specific regs ********/ switch (sd->sensor) { @@ -1637,8 +1600,6 @@ static int mode_init_ov_sensor_regs(struct sd *sd, OV7670_COM7_FMT_MASK); break; case SEN_OV6620: - i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); - break; case SEN_OV6630: i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20); break; @@ -1647,39 +1608,21 @@ static int mode_init_ov_sensor_regs(struct sd *sd, } /******** Palette-specific regs ********/ -/* Need to do work here for the OV7670 */ - -#if 0 - if (win->format == VIDEO_PALETTE_GREY) { - if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { - /* these aren't valid on the OV6620/OV7620/6630? */ - i2c_w_mask(sd, 0x0e, 0x40, 0x40); - } - - /* OV6630 default reg 0x13 value is always right */ - /* OV7640 is 8-bit only */ - if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640) - i2c_w_mask(sd, 0x13, 0x20, 0x20); - else - return -EINVAL; /* No OV6630 greyscale support yet */ - } else { -#endif - if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { - /* not valid on the OV6620/OV7620/6630? */ - i2c_w_mask(sd, 0x0e, 0x00, 0x40); - } + if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { + /* not valid on the OV6620/OV7620/6630? */ + i2c_w_mask(sd, 0x0e, 0x00, 0x40); + } - /* The OV518 needs special treatment. Although both the OV518 - * and the OV6630 support a 16-bit video bus, only the 8 bit Y - * bus is actually used. The UV bus is tied to ground. - * Therefore, the OV6630 needs to be in 8-bit multiplexed - * output mode */ + /* The OV518 needs special treatment. Although both the OV518 + * and the OV6630 support a 16-bit video bus, only the 8 bit Y + * bus is actually used. The UV bus is tied to ground. + * Therefore, the OV6630 needs to be in 8-bit multiplexed + * output mode */ - /* OV7640 is 8-bit only */ + /* OV7640 is 8-bit only */ - if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640) - i2c_w_mask(sd, 0x13, 0x00, 0x20); -/* } */ + if (sd->sensor != SEN_OV6630 && sd->sensor != SEN_OV7640) + i2c_w_mask(sd, 0x13, 0x00, 0x20); /******** Clock programming ********/ /* The OV6620 needs special handling. This prevents the @@ -1688,23 +1631,17 @@ static int mode_init_ov_sensor_regs(struct sd *sd, /* Clock down */ i2c_w(sd, 0x2a, 0x04); - i2c_w(sd, 0x11, win->clockdiv); + i2c_w(sd, 0x11, sd->clockdiv); i2c_w(sd, 0x2a, 0x84); /* This next setting is critical. It seems to improve * the gain or the contrast. The "reserved" bits seem * to have some effect in this case. */ i2c_w(sd, 0x2d, 0x85); - } else if (win->clockdiv >= 0) { - i2c_w(sd, 0x11, win->clockdiv); + } else if (sd->clockdiv >= 0) { + i2c_w(sd, 0x11, sd->clockdiv); } /******** Special Features ********/ -#if 0 -/* not how OV7670 does it! */ - if (framedrop >= 0 && sd->sensor != SEN_OV7640 - && sd->sensor != SEN_OV7670) - i2c_w(sd, 0x16, framedrop); -#endif /* no evidence this is possible with OV7670, either */ /* Test Pattern */ if (sd->sensor != SEN_OV7640 && sd->sensor != SEN_OV7670) @@ -1721,7 +1658,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd, /* is fully tested. */ /* 7620/6620/6630? don't have register 0x35, so play it safe */ if (sd->sensor == SEN_OV7610 || sd->sensor == SEN_OV76BE) { - if (win->width == 640 /*&& win->height == 480*/) + if (!qvga) i2c_w(sd, 0x35, 0x9e); else i2c_w(sd, 0x35, 0x1e); @@ -1729,13 +1666,31 @@ static int mode_init_ov_sensor_regs(struct sd *sd, return 0; } -static int set_ov_sensor_window(struct sd *sd, - struct ovsensor_window *win) +static void sethvflip(struct sd *sd) +{ + if (sd->sensor != SEN_OV7670) + return; + if (sd->gspca_dev.streaming) + ov51x_stop(sd); + i2c_w_mask(sd, OV7670_REG_MVFP, + OV7670_MVFP_MIRROR * sd->hflip + | OV7670_MVFP_VFLIP * sd->vflip, + OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP); + if (sd->gspca_dev.streaming) + ov51x_restart(sd); +} + +static int set_ov_sensor_window(struct sd *sd) { + struct gspca_dev *gspca_dev; + int qvga; int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale; int ret, hstart, hstop, vstop, vstart; __u8 v; + gspca_dev = &sd->gspca_dev; + qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + /* The different sensor ICs handle setting up of window differently. * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */ switch (sd->sensor) { @@ -1780,7 +1735,7 @@ static int set_ov_sensor_window(struct sd *sd, switch (sd->sensor) { case SEN_OV6620: case SEN_OV6630: - if (win->quarter) { /* QCIF */ + if (qvga) { /* QCIF */ hwscale = 0; vwscale = 0; } else { /* CIF */ @@ -1790,7 +1745,7 @@ static int set_ov_sensor_window(struct sd *sd, } break; case SEN_OV8610: - if (win->quarter) { /* QSVGA */ + if (qvga) { /* QSVGA */ hwscale = 1; vwscale = 1; } else { /* SVGA */ @@ -1799,7 +1754,7 @@ static int set_ov_sensor_window(struct sd *sd, } break; default: /* SEN_OV7xx0 */ - if (win->quarter) { /* QVGA */ + if (qvga) { /* QVGA */ hwscale = 1; vwscale = 0; } else { /* VGA */ @@ -1808,7 +1763,7 @@ static int set_ov_sensor_window(struct sd *sd, } } - ret = mode_init_ov_sensor_regs(sd, win); + ret = mode_init_ov_sensor_regs(sd); if (ret < 0) return ret; @@ -1829,7 +1784,7 @@ static int set_ov_sensor_window(struct sd *sd, /* I can hard code this for OV7670s */ /* Yes, these numbers do look odd, but they're tested and work! */ if (sd->sensor == SEN_OV7670) { - if (win->quarter) { /* QVGA from ov7670.c by + if (qvga) { /* QVGA from ov7670.c by * Jonathan Corbet */ hstart = 164; hstop = 20; @@ -1843,82 +1798,45 @@ static int set_ov_sensor_window(struct sd *sd, } /* OV7670 hardware window registers are split across * multiple locations */ - i2c_w(sd, OV7670_REG_HSTART, (hstart >> 3) & 0xff); - i2c_w(sd, OV7670_REG_HSTOP, (hstop >> 3) & 0xff); + i2c_w(sd, OV7670_REG_HSTART, hstart >> 3); + i2c_w(sd, OV7670_REG_HSTOP, hstop >> 3); v = i2c_r(sd, OV7670_REG_HREF); v = (v & 0xc0) | ((hstop & 0x7) << 3) | (hstart & 0x07); msleep(10); /* need to sleep between read and write to * same reg! */ i2c_w(sd, OV7670_REG_HREF, v); - i2c_w(sd, OV7670_REG_VSTART, (vstart >> 2) & 0xff); - i2c_w(sd, OV7670_REG_VSTOP, (vstop >> 2) & 0xff); + i2c_w(sd, OV7670_REG_VSTART, vstart >> 2); + i2c_w(sd, OV7670_REG_VSTOP, vstop >> 2); v = i2c_r(sd, OV7670_REG_VREF); v = (v & 0xc0) | ((vstop & 0x3) << 2) | (vstart & 0x03); msleep(10); /* need to sleep between read and write to * same reg! */ i2c_w(sd, OV7670_REG_VREF, v); - + sethvflip(sd); } else { - i2c_w(sd, 0x17, hwsbase + (win->x >> hwscale)); - i2c_w(sd, 0x18, hwebase + ((win->x + win->width) >> hwscale)); - i2c_w(sd, 0x19, vwsbase + (win->y >> vwscale)); - i2c_w(sd, 0x1a, vwebase + ((win->y + win->height) >> vwscale)); + i2c_w(sd, 0x17, hwsbase); + i2c_w(sd, 0x18, hwebase + (sd->gspca_dev.width >> hwscale)); + i2c_w(sd, 0x19, vwsbase); + i2c_w(sd, 0x1a, vwebase + (sd->gspca_dev.height >> vwscale)); } return 0; } -static int ov_sensor_mode_setup(struct sd *sd, - int width, int height) -{ - struct ovsensor_window win; - -/* win.format = mode; */ - - /* Unless subcapture is enabled, - * center the image window and downsample - * if possible to increase the field of view */ - /* NOTE: OV518(+) and OV519 does downsampling on its own */ - win.width = width; - win.height = height; - if (width == sd->maxwidth) - win.quarter = 0; - else - win.quarter = 1; - - /* Center it */ - win.x = (win.width - width) / 2; - win.y = (win.height - height) / 2; - - /* Clock is determined by OV519 frame rate code */ - win.clockdiv = sd->clockdiv; - - PDEBUG(D_CONF, "Setting clock divider to %d", win.clockdiv); - return set_ov_sensor_window(sd, &win); -} - /* -- start the camera -- */ static void sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int ret; -#if 0 - ret = usb_set_interface(gspca_dev->dev, - gspca_dev->iface, - gspca_dev->alt); - if (ret < 0) - goto out; -#endif - - ret = ov519_mode_init_regs(sd, gspca_dev->width, gspca_dev->height); + ret = ov519_mode_init_regs(sd); if (ret < 0) goto out; - ret = ov_sensor_mode_setup(sd, gspca_dev->width, gspca_dev->height); + ret = set_ov_sensor_window(sd); if (ret < 0) goto out; - ret = ov51x_restart((struct sd *) gspca_dev); + ret = ov51x_restart(sd); if (ret < 0) goto out; PDEBUG(D_STREAM, "camera started alt: 0x%02x", gspca_dev->alt); @@ -1992,12 +1910,10 @@ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int val; -/* int was_streaming; */ val = sd->brightness; PDEBUG(D_CONF, "brightness:%d", val); -/* was_streaming = gspca_dev->streaming; - * if (was_streaming) +/* if (gspca_dev->streaming) * ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV8610: @@ -2015,12 +1931,12 @@ static void setbrightness(struct gspca_dev *gspca_dev) i2c_w(sd, OV7610_REG_BRT, val); break; case SEN_OV7670: -/*jfm - from windblows +/*win trace * i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */ i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val)); break; } -/* if (was_streaming) +/* if (gspca_dev->streaming) * ov51x_restart(sd); */ } @@ -2028,12 +1944,10 @@ static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int val; -/* int was_streaming; */ val = sd->contrast; PDEBUG(D_CONF, "contrast:%d", val); -/* was_streaming = gspca_dev->streaming; - if (was_streaming) +/* if (gspca_dev->streaming) ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV7610: @@ -2070,7 +1984,7 @@ static void setcontrast(struct gspca_dev *gspca_dev) i2c_w(sd, OV7670_REG_CONTRAS, val >> 1); break; } -/* if (was_streaming) +/* if (gspca_dev->streaming) ov51x_restart(sd); */ } @@ -2078,12 +1992,10 @@ static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int val; -/* int was_streaming; */ val = sd->colors; PDEBUG(D_CONF, "saturation:%d", val); -/* was_streaming = gspca_dev->streaming; - if (was_streaming) +/* if (gspca_dev->streaming) ov51x_stop(sd); */ switch (sd->sensor) { case SEN_OV8610: @@ -2109,7 +2021,7 @@ static void setcolors(struct gspca_dev *gspca_dev) /* set REG_COM13 values for UV sat auto mode */ break; } -/* if (was_streaming) +/* if (gspca_dev->streaming) ov51x_restart(sd); */ } @@ -2164,6 +2076,40 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hflip = val; + sethvflip(sd); + return 0; +} + +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hflip; + return 0; +} + +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vflip = val; + sethvflip(sd); + return 0; +} + +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->vflip; + return 0; +} + /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, @@ -2179,21 +2125,20 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x4052), DVNM("Creative Live! VISTA IM")}, - {USB_DEVICE(0x041e, 0x405f), DVNM("Creative Live! VISTA VF0330")}, - {USB_DEVICE(0x041e, 0x4060), DVNM("Creative Live! VISTA VF0350")}, - {USB_DEVICE(0x041e, 0x4061), DVNM("Creative Live! VISTA VF0400")}, - {USB_DEVICE(0x041e, 0x4064), DVNM("Creative Live! VISTA VF0420")}, - {USB_DEVICE(0x041e, 0x4068), DVNM("Creative Live! VISTA VF0470")}, - {USB_DEVICE(0x045e, 0x028c), DVNM("Microsoft xbox cam")}, - {USB_DEVICE(0x054c, 0x0154), DVNM("Sonny toy4")}, - {USB_DEVICE(0x054c, 0x0155), DVNM("Sonny toy5")}, - {USB_DEVICE(0x05a9, 0x0519), DVNM("OmniVision")}, - {USB_DEVICE(0x05a9, 0x0530), DVNM("OmniVision")}, - {USB_DEVICE(0x05a9, 0x4519), DVNM("OmniVision")}, - {USB_DEVICE(0x05a9, 0x8519), DVNM("OmniVision")}, + {USB_DEVICE(0x041e, 0x4052)}, + {USB_DEVICE(0x041e, 0x405f)}, + {USB_DEVICE(0x041e, 0x4060)}, + {USB_DEVICE(0x041e, 0x4061)}, + {USB_DEVICE(0x041e, 0x4064)}, + {USB_DEVICE(0x041e, 0x4068)}, + {USB_DEVICE(0x045e, 0x028c)}, + {USB_DEVICE(0x054c, 0x0154)}, + {USB_DEVICE(0x054c, 0x0155)}, + {USB_DEVICE(0x05a9, 0x0519)}, + {USB_DEVICE(0x05a9, 0x0530)}, + {USB_DEVICE(0x05a9, 0x4519)}, + {USB_DEVICE(0x05a9, 0x8519)}, {} }; #undef DVNAME @@ -2212,6 +2157,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ @@ -2233,4 +2182,3 @@ module_exit(sd_mod_exit); module_param(frame_rate, int, 0644); MODULE_PARM_DESC(frame_rate, "Frame rate (5, 10, 15, 20 or 30 fps)"); - diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c index f79074637..d9668f4cb 100644 --- a/linux/drivers/media/video/gspca/pac207.c +++ b/linux/drivers/media/video/gspca/pac207.c @@ -271,7 +271,6 @@ static int sd_config(struct gspca_dev *gspca_dev, " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x05; cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); @@ -570,17 +569,16 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x4028), DVNM("Creative Webcam Vista Plus")}, - {USB_DEVICE(0x093a, 0x2460), DVNM("Q-Tec Webcam 100")}, - {USB_DEVICE(0x093a, 0x2463), DVNM("Philips spc200nc pac207")}, - {USB_DEVICE(0x093a, 0x2464), DVNM("Labtec Webcam 1200")}, - {USB_DEVICE(0x093a, 0x2468), DVNM("PAC207")}, - {USB_DEVICE(0x093a, 0x2470), DVNM("Genius GF112")}, - {USB_DEVICE(0x093a, 0x2471), DVNM("Genius VideoCam GE111")}, - {USB_DEVICE(0x093a, 0x2472), DVNM("Genius VideoCam GE110")}, - {USB_DEVICE(0x2001, 0xf115), DVNM("D-Link DSB-C120")}, + {USB_DEVICE(0x041e, 0x4028)}, + {USB_DEVICE(0x093a, 0x2460)}, + {USB_DEVICE(0x093a, 0x2463)}, + {USB_DEVICE(0x093a, 0x2464)}, + {USB_DEVICE(0x093a, 0x2468)}, + {USB_DEVICE(0x093a, 0x2470)}, + {USB_DEVICE(0x093a, 0x2471)}, + {USB_DEVICE(0x093a, 0x2472)}, + {USB_DEVICE(0x2001, 0xf115)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -598,6 +596,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index c2d4984cf..94f0cd1b8 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -22,6 +22,7 @@ #define MODULE_NAME "pac7311" #include "gspca.h" +#include "jpeg.h" MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); MODULE_DESCRIPTION("Pixart PAC7311"); @@ -31,16 +32,25 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int avg_lum; + int lum_sum; + atomic_t avg_lum; + atomic_t do_gain; unsigned char brightness; unsigned char contrast; unsigned char colors; unsigned char autogain; + __u8 hflip; + __u8 vflip; + __u8 qindex; - char ffseq; + char tosof; /* number of bytes before next start of frame */ signed char ag_cnt; #define AG_CNT_START 13 + + __u8 sensor; +#define SENSOR_PAC7302 0 +#define SENSOR_PAC7311 1 }; /* V4L2 controls supported by the driver */ @@ -52,6 +62,10 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { { @@ -75,9 +89,10 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Contrast", .minimum = 0, - .maximum = 255, +#define CONTRAST_MAX 255 + .maximum = CONTRAST_MAX, .step = 1, -#define CONTRAST_DEF 127 +#define CONTRAST_DEF 60 .default_value = CONTRAST_DEF, }, .set = sd_setcontrast, @@ -87,9 +102,10 @@ static struct ctrl sd_ctrls[] = { { .id = V4L2_CID_SATURATION, .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", + .name = "Saturation", .minimum = 0, - .maximum = 255, +#define COLOR_MAX 255 + .maximum = COLOR_MAX, .step = 1, #define COLOR_DEF 127 .default_value = COLOR_DEF, @@ -111,101 +127,208 @@ static struct ctrl sd_ctrls[] = { .set = sd_setautogain, .get = sd_getautogain, }, +/* next controls work with pac7302 only */ + { + { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Mirror", + .minimum = 0, + .maximum = 1, + .step = 1, +#define HFLIP_DEF 0 + .default_value = HFLIP_DEF, + }, + .set = sd_sethflip, + .get = sd_gethflip, + }, + { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Vflip", + .minimum = 0, + .maximum = 1, + .step = 1, +#define VFLIP_DEF 0 + .default_value = VFLIP_DEF, + }, + .set = sd_setvflip, + .get = sd_getvflip, + }, }; static struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 2}, - {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 1}, - {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 640, .sizeimage = 640 * 480 * 3 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 0}, }; -#define PAC7311_JPEG_HEADER_SIZE (sizeof pac7311_jpeg_header) /* (594) */ - -static const __u8 pac7311_jpeg_header[] = { - 0xff, 0xd8, - 0xff, 0xe0, 0x00, 0x03, 0x20, - 0xff, 0xc0, 0x00, 0x11, 0x08, - 0x01, 0xe0, /* 12: height */ - 0x02, 0x80, /* 14: width */ - 0x03, /* 16 */ - 0x01, 0x21, 0x00, - 0x02, 0x11, 0x01, - 0x03, 0x11, 0x01, - 0xff, 0xdb, 0x00, 0x84, - 0x00, 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d, - 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a, 0x18, 0x16, - 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d, 0x28, 0x3a, 0x33, 0x3d, - 0x3c, 0x39, 0x33, 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, - 0x44, 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, 0x5f, - 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, 0x79, 0x70, 0x64, - 0x78, 0x5c, 0x65, 0x67, 0x63, 0x01, 0x11, 0x12, 0x12, 0x18, - 0x15, 0x18, 0x2f, 0x1a, 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0xff, 0xc4, 0x01, 0xa2, 0x00, 0x00, 0x01, 0x05, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x10, 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, - 0x04, 0x03, 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d, - 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, - 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, - 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, - 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, - 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, - 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, - 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, - 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, - 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, - 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, - 0xf9, 0xfa, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x0b, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, - 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, - 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, - 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, - 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, - 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, - 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, - 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, - 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, - 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, - 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, - 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, - 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, - 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, - 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, - 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, - 0x11, 0x00, 0x3f, 0x00 +/* pac 7302 */ +static const __u8 probe_7302[] = { +/* index,value */ + 0xff, 0x01, /* page 1 */ + 0x78, 0x00, /* deactivate */ + 0xff, 0x01, + 0x78, 0x40, /* led off */ +}; +static const __u8 start_7302[] = { +/* index, len, [value]* */ + 0xff, 1, 0x00, /* page 0 */ + 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80, + 0x00, 0x00, 0x00, 0x00, + 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00, + 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7, + 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11, + 0x26, 2, 0xaa, 0xaa, + 0x2e, 1, 0x31, + 0x38, 1, 0x01, + 0x3a, 3, 0x14, 0xff, 0x5a, + 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11, + 0x00, 0x54, 0x11, + 0x55, 1, 0x00, + 0x62, 4, 0x10, 0x1e, 0x1e, 0x18, + 0x6b, 1, 0x00, + 0x6e, 3, 0x08, 0x06, 0x00, + 0x72, 3, 0x00, 0xff, 0x00, + 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c, + 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50, + 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00, + 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9, + 0xd2, 0xeb, + 0xaf, 1, 0x02, + 0xb5, 2, 0x08, 0x08, + 0xb8, 2, 0x08, 0x88, + 0xc4, 4, 0xae, 0x01, 0x04, 0x01, + 0xcc, 1, 0x00, + 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9, + 0xc1, 0xd7, 0xec, + 0xdc, 1, 0x01, + 0xff, 1, 0x01, /* page 1 */ + 0x12, 3, 0x02, 0x00, 0x01, + 0x3e, 2, 0x00, 0x00, + 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2, + 0x7c, 1, 0x00, + 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20, + 0x02, 0x00, + 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04, + 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, + 0x07, 0x00, 0x01, 0x07, 0x04, 0x01, + 0xd8, 1, 0x01, + 0xdb, 2, 0x00, 0x01, + 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00, + 0xe6, 4, 0x00, 0x00, 0x00, 0x01, + 0xeb, 1, 0x00, + 0xff, 1, 0x02, /* page 2 */ + 0x22, 1, 0x00, + 0xff, 1, 0x03, /* page 3 */ + 0x00, 255, /* load the page 3 */ + 0x11, 1, 0x01, + 0xff, 1, 0x02, /* page 2 */ + 0x13, 1, 0x00, + 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96, + 0x27, 2, 0x14, 0x0c, + 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22, + 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44, + 0x6e, 1, 0x08, + 0xff, 1, 0x03, /* page 1 */ + 0x78, 1, 0x00, + 0, 0 /* end of sequence */ +}; + +/* page 3 - the value 0xaa says skip the index - see reg_w_page() */ +static const __u8 page3_7302[] = { + 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16, + 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, + 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00, + 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21, + 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54, + 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8, + 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, + 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00, + 0x00 +}; + +/* pac 7311 */ +static const __u8 probe_7311[] = { + 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */ + 0x78, 0x40, /* Bit_0=start stream, Bit_7=LED */ + 0x78, 0x44, /* Bit_0=start stream, Bit_7=LED */ + 0xff, 0x04, + 0x27, 0x80, + 0x28, 0xca, + 0x29, 0x53, + 0x2a, 0x0e, + 0xff, 0x01, + 0x3e, 0x20, +}; + +static const __u8 start_7311[] = { +/* index, len, [value]* */ + 0xff, 1, 0x01, /* page 1 */ + 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00, + 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c, + 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e, + 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49, + 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48, + 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78, + 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b, + 0xd0, 0xff, + 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80, + 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84, + 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14, + 0x18, 0x20, + 0x96, 3, 0x01, 0x08, 0x04, + 0xa0, 4, 0x44, 0x44, 0x44, 0x04, + 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00, + 0x3f, 0x00, 0x0a, 0x01, 0x00, + 0xff, 1, 0x04, /* page 4 */ + 0x00, 254, /* load the page 4 */ + 0x11, 1, 0x01, + 0, 0 /* end of sequence */ +}; + +/* page 4 - the value 0xaa says skip the index - see reg_w_page() */ +static const __u8 page4_7311[] = { + 0xaa, 0xaa, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f, + 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62, + 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa, + 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01, + 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x28, 0x04, 0x11, 0x00, 0x00 }; static void reg_w_buf(struct gspca_dev *gspca_dev, - __u16 index, - const char *buffer, __u16 len) + __u8 index, + const char *buffer, int len) { memcpy(gspca_dev->usb_buf, buffer, len); usb_control_msg(gspca_dev->dev, @@ -218,7 +341,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, } static __u8 reg_r(struct gspca_dev *gspca_dev, - __u16 index) + __u8 index) { usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), @@ -231,7 +354,7 @@ static __u8 reg_r(struct gspca_dev *gspca_dev, } static void reg_w(struct gspca_dev *gspca_dev, - __u16 index, + __u8 index, __u8 value) { gspca_dev->usb_buf[0] = value; @@ -243,6 +366,74 @@ static void reg_w(struct gspca_dev *gspca_dev, 500); } +static void reg_w_seq(struct gspca_dev *gspca_dev, + const __u8 *seq, int len) +{ + while (--len >= 0) { + reg_w(gspca_dev, seq[0], seq[1]); + seq += 2; + } +} + +/* load the beginning of a page */ +static void reg_w_page(struct gspca_dev *gspca_dev, + const __u8 *page, int len) +{ + int index; + + for (index = 0; index < len; index++) { + if (page[index] == 0xaa) /* skip this index */ + continue; + gspca_dev->usb_buf[0] = page[index]; + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, gspca_dev->usb_buf, 1, + 500); + } +} + +/* output a variable sequence */ +static void reg_w_var(struct gspca_dev *gspca_dev, + const __u8 *seq) +{ + int index, len; + + for (;;) { + index = *seq++; + len = *seq++; + switch (len) { + case 0: + return; + case 254: + reg_w_page(gspca_dev, page4_7311, sizeof page4_7311); + break; + case 255: + reg_w_page(gspca_dev, page3_7302, sizeof page3_7302); + break; + default: + if (len > 32) { + PDEBUG(D_ERR|D_STREAM, + "Incorrect variable sequence"); + return; + } + while (len > 0) { + if (len < 8) { + reg_w_buf(gspca_dev, index, seq, len); + seq += len; + break; + } + reg_w_buf(gspca_dev, index, seq, 8); + seq += 8; + index += 8; + len -= 8; + } + } + } + /* not reached */ +} + /* this function is called at probe time */ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) @@ -250,40 +441,75 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - PDEBUG(D_CONF, "Find Sensor PAC7311"); - reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x40); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x27, 0x80); - reg_w(gspca_dev, 0x28, 0xca); - reg_w(gspca_dev, 0x29, 0x53); - reg_w(gspca_dev, 0x2a, 0x0e); - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x3e, 0x20); - cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x05; - cam->cam_mode = vga_mode; - cam->nmodes = ARRAY_SIZE(vga_mode); + + sd->sensor = id->driver_info; + if (sd->sensor == SENSOR_PAC7302) { + PDEBUG(D_CONF, "Find Sensor PAC7302"); + reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302); + + cam->cam_mode = &vga_mode[2]; /* only 640x480 */ + cam->nmodes = 1; + } else { + PDEBUG(D_CONF, "Find Sensor PAC7311"); + reg_w_seq(gspca_dev, probe_7302, sizeof probe_7302); + + cam->cam_mode = vga_mode; + cam->nmodes = ARRAY_SIZE(vga_mode); + } sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; sd->colors = COLOR_DEF; sd->autogain = AUTOGAIN_DEF; + sd->hflip = HFLIP_DEF; + sd->vflip = VFLIP_DEF; + sd->qindex = 3; + sd->ag_cnt = -1; return 0; } +/* rev 12a only */ +static void setbrightcont(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i, v; + static const __u8 max[10] = + {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, + 0xd4, 0xec}; + static const __u8 delta[10] = + {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17, + 0x11, 0x0b}; + + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + for (i = 0; i < 10; i++) { + v = max[i]; + v += (sd->brightness - BRIGHTNESS_MAX) + * 150 / BRIGHTNESS_MAX; /* 200 ? */ + v -= delta[i] * sd->contrast / CONTRAST_MAX; + if (v < 0) + v = 0; + else if (v > 0xff) + v = 0xff; + reg_w(gspca_dev, 0xa2 + i, v); + } + reg_w(gspca_dev, 0xdc, 0x01); +} + static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int brightness; + if (sd->sensor == SENSOR_PAC7302) { + setbrightcont(gspca_dev); + return; + } /*jfm: inverted?*/ brightness = BRIGHTNESS_MAX - sd->brightness; reg_w(gspca_dev, 0xff, 0x04); -/* reg_w(gspca_dev, 0x0e, 0x00); */ + reg_w(gspca_dev, 0x0e, 0x00); reg_w(gspca_dev, 0x0f, brightness); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); @@ -294,28 +520,75 @@ static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (sd->sensor == SENSOR_PAC7302) { + setbrightcont(gspca_dev); + return; + } reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x80, sd->contrast); + reg_w(gspca_dev, 0x10, sd->contrast); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); - PDEBUG(D_CONF|D_STREAM, "contrast: %i", sd->contrast); } static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (sd->sensor == SENSOR_PAC7302) { + int i, v; + static const int a[9] = + {217, -212, 0, -101, 170, -67, -38, -315, 355}; + static const int b[9] = + {19, 106, 0, 19, 106, 1, 19, 106, 1}; + + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + reg_w(gspca_dev, 0x11, 0x01); + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ + for (i = 0; i < 9; i++) { + v = a[i] * sd->colors / COLOR_MAX + b[i]; + reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); + reg_w(gspca_dev, 0x0f + 2 * i + 1, v); + } + reg_w(gspca_dev, 0xdc, 0x01); + return; + } reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x10, sd->colors); + reg_w(gspca_dev, 0x80, sd->colors); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); } +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->autogain) { + sd->lum_sum = 0; + sd->ag_cnt = AG_CNT_START; + } else { + sd->ag_cnt = -1; + } +} + +/* this function is used by pac7302 only */ +static void sethvflip(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 data; + + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + data = (sd->hflip ? 0x00 : 0x08) + | (sd->vflip ? 0x04 : 0x00); + reg_w(gspca_dev, 0x21, data); + reg_w(gspca_dev, 0x11, 0x01); +} + /* this function is called at open time */ static int sd_open(struct gspca_dev *gspca_dev) { - reg_w(gspca_dev, 0x78, 0x00); /* Turn on LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Turn on LED */ return 0; } @@ -323,126 +596,71 @@ static void sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - reg_w(gspca_dev, 0xff, 0x01); - reg_w_buf(gspca_dev, 0x0002, "\x48\x0a\x40\x08\x00\x00\x08\x00", 8); - reg_w_buf(gspca_dev, 0x000a, "\x06\xff\x11\xff\x5a\x30\x90\x4c", 8); - reg_w_buf(gspca_dev, 0x0012, "\x00\x07\x00\x0a\x10\x00\xa0\x10", 8); - reg_w_buf(gspca_dev, 0x001a, "\x02\x00\x00\x00\x00\x0b\x01\x00", 8); - reg_w_buf(gspca_dev, 0x0022, "\x00\x00\x00\x00\x00\x00\x00\x00", 8); - reg_w_buf(gspca_dev, 0x002a, "\x00\x00\x00", 3); - reg_w_buf(gspca_dev, 0x003e, "\x00\x00\x78\x52\x4a\x52\x78\x6e", 8); - reg_w_buf(gspca_dev, 0x0046, "\x48\x46\x48\x6e\x5f\x49\x42\x49", 8); - reg_w_buf(gspca_dev, 0x004e, "\x5f\x5f\x49\x42\x49\x5f\x6e\x48", 8); - reg_w_buf(gspca_dev, 0x0056, "\x46\x48\x6e\x78\x52\x4a\x52\x78", 8); - reg_w_buf(gspca_dev, 0x005e, "\x00\x00\x09\x1b\x34\x49\x5c\x9b", 8); - reg_w_buf(gspca_dev, 0x0066, "\xd0\xff", 2); - reg_w_buf(gspca_dev, 0x0078, "\x44\x00\xf2\x01\x01\x80", 6); - reg_w_buf(gspca_dev, 0x007f, "\x2a\x1c\x00\xc8\x02\x58\x03\x84", 8); - reg_w_buf(gspca_dev, 0x0087, "\x12\x00\x1a\x04\x08\x0c\x10\x14", 8); - reg_w_buf(gspca_dev, 0x008f, "\x18\x20", 2); - reg_w_buf(gspca_dev, 0x0096, "\x01\x08\x04", 3); - reg_w_buf(gspca_dev, 0x00a0, "\x44\x44\x44\x04", 4); - reg_w_buf(gspca_dev, 0x00f0, "\x01\x00\x00\x00\x22\x00\x20\x00", 8); - reg_w_buf(gspca_dev, 0x00f8, "\x3f\x00\x0a\x01\x00", 5); + sd->tosof = 0; + + if (sd->sensor == SENSOR_PAC7302) + reg_w_var(gspca_dev, start_7302); + else + reg_w_var(gspca_dev, start_7311); - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x02, 0x04); - reg_w(gspca_dev, 0x03, 0x54); - reg_w(gspca_dev, 0x04, 0x07); - reg_w(gspca_dev, 0x05, 0x2b); - reg_w(gspca_dev, 0x06, 0x09); - reg_w(gspca_dev, 0x07, 0x0f); - reg_w(gspca_dev, 0x08, 0x09); - reg_w(gspca_dev, 0x09, 0x00); - reg_w(gspca_dev, 0x0c, 0x07); - reg_w(gspca_dev, 0x0d, 0x00); - reg_w(gspca_dev, 0x0e, 0x00); - reg_w(gspca_dev, 0x0f, 0x62); - reg_w(gspca_dev, 0x10, 0x08); - reg_w(gspca_dev, 0x12, 0x07); - reg_w(gspca_dev, 0x13, 0x00); - reg_w(gspca_dev, 0x14, 0x00); - reg_w(gspca_dev, 0x15, 0x00); - reg_w(gspca_dev, 0x16, 0x00); - reg_w(gspca_dev, 0x17, 0x00); - reg_w(gspca_dev, 0x18, 0x00); - reg_w(gspca_dev, 0x19, 0x00); - reg_w(gspca_dev, 0x1a, 0x00); - reg_w(gspca_dev, 0x1b, 0x03); - reg_w(gspca_dev, 0x1c, 0xa0); - reg_w(gspca_dev, 0x1d, 0x01); - reg_w(gspca_dev, 0x1e, 0xf4); - reg_w(gspca_dev, 0x21, 0x00); - reg_w(gspca_dev, 0x22, 0x08); - reg_w(gspca_dev, 0x24, 0x03); - reg_w(gspca_dev, 0x26, 0x00); - reg_w(gspca_dev, 0x27, 0x01); - reg_w(gspca_dev, 0x28, 0xca); - reg_w(gspca_dev, 0x29, 0x10); - reg_w(gspca_dev, 0x2a, 0x06); - reg_w(gspca_dev, 0x2b, 0x78); - reg_w(gspca_dev, 0x2c, 0x00); - reg_w(gspca_dev, 0x2d, 0x00); - reg_w(gspca_dev, 0x2e, 0x00); - reg_w(gspca_dev, 0x2f, 0x00); - reg_w(gspca_dev, 0x30, 0x23); - reg_w(gspca_dev, 0x31, 0x28); - reg_w(gspca_dev, 0x32, 0x04); - reg_w(gspca_dev, 0x33, 0x11); - reg_w(gspca_dev, 0x34, 0x00); - reg_w(gspca_dev, 0x35, 0x00); - reg_w(gspca_dev, 0x11, 0x01); setcontrast(gspca_dev); setbrightness(gspca_dev); setcolors(gspca_dev); + setautogain(gspca_dev); /* set correct resolution */ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { - case 2: /* 160x120 */ + case 2: /* 160x120 pac7311 */ reg_w(gspca_dev, 0xff, 0x04); reg_w(gspca_dev, 0x02, 0x03); reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x08, 0x09); reg_w(gspca_dev, 0x17, 0x20); reg_w(gspca_dev, 0x1b, 0x00); -/* reg_w(gspca_dev, 0x80, 0x69); */ reg_w(gspca_dev, 0x87, 0x10); break; - case 1: /* 320x240 */ + case 1: /* 320x240 pac7311 */ reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x02, 0x03); + reg_w(gspca_dev, 0x02, 0x07); reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x08, 0x09); reg_w(gspca_dev, 0x17, 0x30); -/* reg_w(gspca_dev, 0x80, 0x3f); */ reg_w(gspca_dev, 0x87, 0x11); break; case 0: /* 640x480 */ + if (sd->sensor == SENSOR_PAC7302) + break; reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x02, 0x03); + reg_w(gspca_dev, 0x02, 0x07); reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x08, 0x08); reg_w(gspca_dev, 0x17, 0x00); -/* reg_w(gspca_dev, 0x80, 0x1c); */ reg_w(gspca_dev, 0x87, 0x12); break; } /* start stream */ reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x78, 0x04); - reg_w(gspca_dev, 0x78, 0x05); - - if (sd->autogain) { - sd->ag_cnt = AG_CNT_START; - sd->avg_lum = 0; + if (sd->sensor == SENSOR_PAC7302) { + sethvflip(gspca_dev); + reg_w(gspca_dev, 0x78, 0x01); + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x01); } else { - sd->ag_cnt = -1; + reg_w(gspca_dev, 0x78, 0x44); + reg_w(gspca_dev, 0x78, 0x45); } } static void sd_stopN(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0x78, 0x00); + reg_w(gspca_dev, 0x78, 0x00); + return; + } reg_w(gspca_dev, 0xff, 0x04); reg_w(gspca_dev, 0x27, 0x80); reg_w(gspca_dev, 0x28, 0xca); @@ -450,37 +668,40 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x2a, 0x0e); reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x3e, 0x20); - reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ } static void sd_stop0(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0xff, 0x01); + reg_w(gspca_dev, 0x78, 0x40); + } } /* this function is called at close time */ static void sd_close(struct gspca_dev *gspca_dev) { - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x27, 0x80); - reg_w(gspca_dev, 0x28, 0xca); - reg_w(gspca_dev, 0x29, 0x53); - reg_w(gspca_dev, 0x2a, 0x0e); - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x3e, 0x20); - reg_w(gspca_dev, 0x78, 0x04); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ - reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_7=LED */ } -static void setautogain(struct gspca_dev *gspca_dev, int luma) +static void do_autogain(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + int luma; int luma_mean = 128; int luma_delta = 20; __u8 spring = 5; int Gbright; + if (!atomic_read(&sd->do_gain)) + return; + atomic_set(&sd->do_gain, 0); + + luma = atomic_read(&sd->avg_lum); Gbright = reg_r(gspca_dev, 0x02); PDEBUG(D_FRAM, "luma mean %d", luma); if (luma < luma_mean - luma_delta || @@ -491,143 +712,120 @@ static void setautogain(struct gspca_dev *gspca_dev, int luma) else if (Gbright < 4) Gbright = 4; PDEBUG(D_FRAM, "gbright %d", Gbright); - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x0f, Gbright); - /* load registers to sensor (Bit 0, auto clear) */ - reg_w(gspca_dev, 0x11, 0x01); + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0xff, 0x03); + reg_w(gspca_dev, 0x10, Gbright); + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); + } else { + reg_w(gspca_dev, 0xff, 0x04); + reg_w(gspca_dev, 0x0f, Gbright); + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); + } } } +/* this function is run at interrupt level */ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; - unsigned char tmpbuf[4]; - int i, p, ffseq; - -/* if (len < 5) { */ - if (len < 6) { -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; - } - - ffseq = sd->ffseq; - - for (p = 0; p < len - 6; p++) { - if ((data[0 + p] == 0xff) - && (data[1 + p] == 0xff) - && (data[2 + p] == 0x00) - && (data[3 + p] == 0xff) - && (data[4 + p] == 0x96)) { - - /* start of frame */ - if (sd->ag_cnt >= 0 && p > 28) { - sd->avg_lum += data[p - 23]; - if (--sd->ag_cnt < 0) { - sd->ag_cnt = AG_CNT_START; - setautogain(gspca_dev, - sd->avg_lum / AG_CNT_START); - sd->avg_lum = 0; - } + int i; + +#define INTER_FRAME 0x53 /* eof + inter frame + sof */ +#define LUM_OFFSET 0x1e /* reverse offset / start of frame */ + +#if 0 /*fixme:test+*/ +/* dump the packet */ + if (gspca_debug & 0x200) { + static char tmp[50]; + + PDEBUG(0x200, "pkt_scan"); + tmp[0] = 0; + for (i = 0; i < len; i++) { + if (i % 16 == 0 && i != 0) { + PDEBUG(0x200, "%s", tmp); + tmp[0] = 0; } - - /* copy the end of data to the current frame */ - frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, - data, p); - - /* put the JPEG header in the new frame */ - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, - (unsigned char *) pac7311_jpeg_header, - 12); - tmpbuf[0] = gspca_dev->height >> 8; - tmpbuf[1] = gspca_dev->height & 0xff; - tmpbuf[2] = gspca_dev->width >> 8; - tmpbuf[3] = gspca_dev->width & 0xff; - gspca_frame_add(gspca_dev, INTER_PACKET, frame, - tmpbuf, 4); - gspca_frame_add(gspca_dev, INTER_PACKET, frame, - (unsigned char *) &pac7311_jpeg_header[16], - PAC7311_JPEG_HEADER_SIZE - 16); - - data += p + 7; - len -= p + 7; - ffseq = 0; - break; + sprintf(&tmp[(i % 16) * 3], "%02x ", data[i]); } + if (tmp[0] != 0) + PDEBUG(0x200, "%s", tmp); } - - /* remove the 'ff ff ff xx' sequences */ - switch (ffseq) { - case 3: - data += 1; - len -= 1; - break; - case 2: - if (data[0] == 0xff) { - data += 2; - len -= 2; - frame->data_end -= 2; - } - break; - case 1: - if (data[0] == 0xff - && data[1] == 0xff) { - data += 3; - len -= 3; - frame->data_end -= 1; - } - break; +#endif /*fixme:test-*/ + /* + * inside a frame, there may be: + * escaped ff ('ff 00') + * sequences'ff ff ff xx' to remove + * end of frame ('ff d9') + * at the end of frame, there are: + * ff d9 end of frame + * 0x33 bytes + * one byte luminosity + * 0x16 bytes + * ff ff 00 ff 96 62 44 start of frame + */ + + if (sd->tosof != 0) { /* if outside a frame */ + + /* get the luminosity and go to the start of frame */ + data += sd->tosof; + len -= sd->tosof; + if (sd->tosof > LUM_OFFSET) + sd->lum_sum += data[-LUM_OFFSET]; + sd->tosof = 0; + jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21); } - for (i = 0; i < len - 4; i++) { - if (data[i] == 0xff - && data[i + 1] == 0xff - && data[i + 2] == 0xff) { - memmove(&data[i], &data[i + 4], len - i - 4); - len -= 4; + + for (i = 0; i < len; i++) { + if (data[i] != 0xff) + continue; + switch (data[i + 1]) { + case 0xd9: /* 'ff d9' end of frame */ + frame = gspca_frame_add(gspca_dev, + LAST_PACKET, + frame, data, i + 2); + data += i + INTER_FRAME; + len -= i + INTER_FRAME; + i = 0; + if (len > -LUM_OFFSET) + sd->lum_sum += data[-LUM_OFFSET]; + if (len < 0) { + sd->tosof = -len; + break; + } + jpeg_put_header(gspca_dev, frame, sd->qindex, 0x21); + break; +#if 0 /*fixme:test+*/ +/* is there a start of frame ? */ + case 0xff: /* 'ff ff' */ + if (data[i + 2] == 0x00) { + static __u8 ffd9[2] = {0xff, 0xd9}; + + gspca_frame_add(gspca_dev, + INTER_PACKET, + frame, data, + i + 7 - INTER_FRAME); + frame = gspca_frame_add(gspca_dev, + LAST_PACKET, + frame, ffd9, 2); + data += i + 7; + len -= i + 7; + i = 0; + jpeg_put_header(gspca_dev, frame, + sd->qindex, 0x21); + break; + } + break; +#endif /*fixme:test-*/ } } - ffseq = 0; - if (data[len - 4] == 0xff) { - if (data[len - 3] == 0xff - && data[len - 2] == 0xff) { - len -= 4; - } - } else if (data[len - 3] == 0xff) { - if (data[len - 2] == 0xff - && data[len - 1] == 0xff) - ffseq = 3; - } else if (data[len - 2] == 0xff) { - if (data[len - 1] == 0xff) - ffseq = 2; - } else if (data[len - 1] == 0xff) - ffseq = 1; - sd->ffseq = ffseq; - gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); -} - -static void getbrightness(struct gspca_dev *gspca_dev) -{ -/* sd->brightness = reg_r(gspca_dev, 0x08); - return sd->brightness; */ -/* PDEBUG(D_CONF, "Called pac7311_getbrightness: Not implemented yet"); */ -} - -#if 0 -static void getcontrast(struct gspca_dev *gspca_dev) -{ -/* sd->contrast = reg_r(gspca_dev, 0x0e); - return sd->contrast; */ - PDEBUG(D_CONF, "getcontrast: Not implemented yet"); -} -#endif - -#if 0 -static void getcolors(struct gspca_dev *gspca_dev) -{ + gspca_frame_add(gspca_dev, INTER_PACKET, + frame, data, i); } -#endif static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { @@ -643,7 +841,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - getbrightness(gspca_dev); *val = sd->brightness; return 0; } @@ -662,7 +859,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; -/* getcontrast(gspca_dev); */ *val = sd->contrast; return 0; } @@ -681,7 +877,6 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; -/* getcolors(gspca_dev); */ *val = sd->colors; return 0; } @@ -691,12 +886,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->autogain = val; - if (val) { - sd->ag_cnt = AG_CNT_START; - sd->avg_lum = 0; - } else { - sd->ag_cnt = -1; - } + if (gspca_dev->streaming) + setautogain(gspca_dev); return 0; } @@ -708,6 +899,42 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->hflip = val; + if (gspca_dev->streaming) + sethvflip(gspca_dev); + return 0; +} + +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->hflip; + return 0; +} + +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vflip = val; + if (gspca_dev->streaming) + sethvflip(gspca_dev); + return 0; +} + +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->vflip; + return 0; +} + /* sub-driver description */ static struct sd_desc sd_desc = { .name = MODULE_NAME, @@ -720,19 +947,18 @@ static struct sd_desc sd_desc = { .stop0 = sd_stop0, .close = sd_close, .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x093a, 0x2600), DVNM("Typhoon")}, - {USB_DEVICE(0x093a, 0x2601), DVNM("Philips SPC610NC")}, - {USB_DEVICE(0x093a, 0x2603), DVNM("PAC7312")}, - {USB_DEVICE(0x093a, 0x2608), DVNM("Trust WB-3300p")}, - {USB_DEVICE(0x093a, 0x260e), DVNM("Gigaware VGA PC Camera")}, - /* and also ', Trust WB-3350p, SIGMA cam 2350' */ - {USB_DEVICE(0x093a, 0x260f), DVNM("SnakeCam")}, - {USB_DEVICE(0x093a, 0x2621), DVNM("PAC731x")}, + {USB_DEVICE(0x093a, 0x2600), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2601), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2603), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -750,6 +976,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/sonixb.c b/linux/drivers/media/video/gspca/sonixb.c index bfe0ae346..afbb969ba 100644 --- a/linux/drivers/media/video/gspca/sonixb.c +++ b/linux/drivers/media/video/gspca/sonixb.c @@ -41,25 +41,29 @@ struct sd { unsigned char brightness; unsigned char autogain; unsigned char autogain_ignore_frames; + unsigned char frames_to_drop; unsigned char freq; /* light freq filter setting */ - unsigned char saturation; - unsigned char hue; - unsigned char contrast; unsigned char fr_h_sz; /* size of frame header */ char sensor; /* Type of image sensor chip */ #define SENSOR_HV7131R 0 #define SENSOR_OV6650 1 #define SENSOR_OV7630 2 -#define SENSOR_OV7630_3 3 -#define SENSOR_PAS106 4 -#define SENSOR_PAS202 5 -#define SENSOR_TAS5110 6 -#define SENSOR_TAS5130CXX 7 +#define SENSOR_PAS106 3 +#define SENSOR_PAS202 4 +#define SENSOR_TAS5110 5 +#define SENSOR_TAS5130CXX 6 char sensor_has_gain; __u8 sensor_addr; + __u8 reg11; }; +/* flags used in the device id table */ +#define F_GAIN 0x01 /* has gain */ +#define F_AUTO 0x02 /* has autogain */ +#define F_SIF 0x04 /* sif or vga */ +#define F_H18 0x08 /* long (18 b) or short (12 b) frame header */ + #define COMP2 0x8f #define COMP 0xc7 /* 0x87 //0x07 */ #define COMP1 0xc9 /* 0x89 //0x09 */ @@ -89,12 +93,6 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val); -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { { @@ -171,48 +169,6 @@ static struct ctrl sd_ctrls[] = { .set = sd_setfreq, .get = sd_getfreq, }, - { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 255, - .step = 1, -#define SATURATION_DEF 127 - .default_value = SATURATION_DEF, - }, - .set = sd_setsaturation, - .get = sd_getsaturation, - }, - { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = 0, - .maximum = 255, - .step = 1, -#define HUE_DEF 127 - .default_value = HUE_DEF, - }, - .set = sd_sethue, - .get = sd_gethue, - }, - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, -#define CONTRAST_DEF 127 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, }; static struct v4l2_pix_format vga_mode[] = { @@ -245,8 +201,6 @@ static struct v4l2_pix_format sif_mode[] = { .priv = 0}, }; -static const __u8 probe_ov7630[] = {0x08, 0x44}; - static const __u8 initHv7131[] = { 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -351,7 +305,7 @@ static const __u8 initOv7630_3[] = { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */ 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */ }; -static const __u8 ov7630_sensor_init_com[][8] = { +static const __u8 ov7630_sensor_init[][8] = { {0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, {0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10}, /* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */ @@ -372,17 +326,6 @@ static const __u8 ov7630_sensor_init_com[][8] = { {0xa0, 0x21, 0x7d, 0xf7, 0x8e, 0x00, 0x30, 0x10}, {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10}, }; -static const __u8 ov7630_sensor_init[][8] = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 200ms */ - {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x10}, /* jfm */ - {0xa0, 0x21, 0x10, 0x57, 0xbd, 0x06, 0xf6, 0x16}, - {0xa0, 0x21, 0x76, 0x02, 0xbd, 0x06, 0xf6, 0x16}, - {0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */ -}; -static const __u8 ov7630_sensor_init_3[][8] = { - {0xa0, 0x21, 0x2a, 0xa0, 0x00, 0x00, 0x00, 0x10}, - {0xa0, 0x21, 0x2a, 0x80, 0x00, 0x00, 0x00, 0x10}, -}; static const __u8 initPas106[] = { 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00, @@ -498,7 +441,7 @@ static void reg_w(struct gspca_dev *gspca_dev, const __u8 *buffer, int len) { -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG if (len > sizeof gspca_dev->usb_buf) { PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow"); return; @@ -572,7 +515,6 @@ static void setbrightness(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_OV6650: - case SENSOR_OV7630_3: case SENSOR_OV7630: { __u8 i2cOV[] = {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}; @@ -665,7 +607,7 @@ static void setsensorgain(struct gspca_dev *gspca_dev) case SENSOR_OV6650: gain >>= 1; /* fall thru */ - case SENSOR_OV7630_3: { + case SENSOR_OV7630: { __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; i2c[1] = sd->sensor_addr; @@ -720,7 +662,7 @@ static void setexposure(struct gspca_dev *gspca_dev) break; } case SENSOR_OV6650: - case SENSOR_OV7630_3: { + case SENSOR_OV7630: { /* The ov6650 / ov7630 have 2 registers which both influence exposure, register 11, whose low nibble sets the nr off fps according to: fps = 30 / (low_nibble + 1) @@ -735,16 +677,20 @@ static void setexposure(struct gspca_dev *gspca_dev) The code maps our 0 - 510 ms exposure ctrl to these 2 registers, trying to keep fps as high as possible. */ - __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0xc0, 0x00, 0x00, 0x10}; - int reg10, reg11; + __u8 i2c[] = {0xb0, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10}; + int reg10, reg11, reg10_max; + /* ov6645 datasheet says reg10_max is 9a, but that uses tline * 2 * reg10 as formula for calculating texpo, the ov6650 probably uses the same formula as the 7730 which uses tline * 4 * reg10, which explains why the reg10max we've found experimentally for the ov6650 is exactly half that of the ov6645. The ov7630 datasheet says the max is 0x41. */ - const int reg10_max = (sd->sensor == SENSOR_OV6650) - ? 0x4d : 0x41; + if (sd->sensor == SENSOR_OV6650) { + reg10_max = 0x4d; + i2c[4] = 0xc0; /* OV6650 needs non default vsync pol */ + } else + reg10_max = 0x41; reg11 = (60 * sd->exposure + 999) / 1000; if (reg11 < 1) @@ -765,20 +711,23 @@ static void setexposure(struct gspca_dev *gspca_dev) else if (reg10 > reg10_max) reg10 = reg10_max; + /* In 640x480, if the reg11 has less than 3, the image is + unstable (not enough bandwidth). */ + if (gspca_dev->width == 640 && reg11 < 3) + reg11 = 3; + /* Write reg 10 and reg11 low nibble */ i2c[1] = sd->sensor_addr; i2c[3] = reg10; i2c[4] |= reg11 - 1; - if (sd->sensor == SENSOR_OV7630_3) { - __u8 reg76 = reg10 & 0x03; - __u8 i2c_reg76[] = {0xa0, 0x21, 0x76, 0x00, - 0x00, 0x00, 0x00, 0x10}; - reg10 >>= 2; - i2c_reg76[3] = reg76; - if (i2c_w(gspca_dev, i2c_reg76) < 0) - PDEBUG(D_ERR, "i2c error exposure"); - } - if (i2c_w(gspca_dev, i2c) < 0) + + /* If register 11 didn't change, don't change it */ + if (sd->reg11 == reg11 ) + i2c[0] = 0xa0; + + if (i2c_w(gspca_dev, i2c) == 0) + sd->reg11 = reg11; + else PDEBUG(D_ERR, "i2c error exposure"); break; } @@ -791,11 +740,11 @@ static void setfreq(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_OV6650: - case SENSOR_OV7630_3: { + case SENSOR_OV7630: { /* Framerate adjust register for artificial light 50 hz flicker - compensation, identical to ov6630 0x2b register, see ov6630 - datasheet. - 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */ + compensation, for the ov6650 this is identical to ov6630 + 0x2b register, see ov6630 datasheet. + 0x4f / 0x8a -> (30 fps -> 25 fps), 0x00 -> no adjustment */ __u8 i2c[] = {0xa0, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}; switch (sd->freq) { default: @@ -816,69 +765,6 @@ static void setfreq(struct gspca_dev *gspca_dev) } } -static void setsaturation(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->sensor) { -/* case SENSOR_OV6650: */ - case SENSOR_OV7630_3: - case SENSOR_OV7630: { - __u8 i2c[] = {0xa0, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}; - i2c[1] = sd->sensor_addr; - i2c[3] = sd->saturation & 0xf0; - if (i2c_w(gspca_dev, i2c) < 0) - PDEBUG(D_ERR, "i2c error setsaturation"); - else - PDEBUG(D_CONF, "saturation set to: %d", - (int)sd->saturation); - break; - } - } -} - -static void sethue(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->sensor) { -/* case SENSOR_OV6650: */ - case SENSOR_OV7630_3: - case SENSOR_OV7630: { - __u8 i2c[] = {0xa0, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10}; - i2c[1] = sd->sensor_addr; - i2c[3] = 0x20 | (sd->hue >> 3); - if (i2c_w(gspca_dev, i2c) < 0) - PDEBUG(D_ERR, "i2c error setsaturation"); - else - PDEBUG(D_CONF, "hue set to: %d", (int)sd->hue); - break; - } - } -} - -static void setcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->sensor) { -/* case SENSOR_OV6650: */ - case SENSOR_OV7630_3: - case SENSOR_OV7630: { - __u8 i2c[] = {0xa0, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10}; - i2c[1] = sd->sensor_addr; - i2c[3] = 0x20 | (sd->contrast >> 3); - if (i2c_w(gspca_dev, i2c) < 0) - PDEBUG(D_ERR, "i2c error setcontrast"); - else - PDEBUG(D_CONF, "contrast set to: %d", - (int)sd->contrast); - break; - } - } -} - - static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -904,88 +790,32 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 product; int sif = 0; /* nctrls depends upon the sensor, so we use a per cam copy */ memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc)); gspca_dev->sd_desc = &sd->sd_desc; - sd->fr_h_sz = 12; /* default size of the frame header */ - sd->sd_desc.nctrls = 2; /* default nb of ctrls */ - sd->autogain = AUTOGAIN_DEF; /* default is autogain active */ - - product = id->idProduct; -/* switch (id->idVendor) { */ -/* case 0x0c45: * Sonix */ - switch (product) { - case 0x6001: /* SN9C102 */ - case 0x6005: /* SN9C101 */ - case 0x6007: /* SN9C101 */ - sd->sensor = SENSOR_TAS5110; - sd->sensor_has_gain = 1; - sd->sd_desc.nctrls = 4; - sd->sd_desc.dq_callback = do_autogain; - sif = 1; - break; - case 0x6009: /* SN9C101 */ - case 0x600d: /* SN9C101 */ - case 0x6029: /* SN9C101 */ - sd->sensor = SENSOR_PAS106; - sif = 1; - break; - case 0x6011: /* SN9C101 - SN9C101G */ - sd->sensor = SENSOR_OV6650; - sd->sensor_has_gain = 1; - sd->sensor_addr = 0x60; - sd->sd_desc.nctrls = 5; - sd->sd_desc.dq_callback = do_autogain; - sif = 1; - break; - case 0x6019: /* SN9C101 */ - case 0x602c: /* SN9C102 */ - case 0x602e: /* SN9C102 */ - sd->sensor = SENSOR_OV7630; - sd->sensor_addr = 0x21; - break; - case 0x60b0: /* SN9C103 */ - sd->sensor = SENSOR_OV7630_3; - sd->sensor_addr = 0x21; - sd->fr_h_sz = 18; /* size of frame header */ - sd->sensor_has_gain = 1; - sd->sd_desc.nctrls = 8; - sd->sd_desc.dq_callback = do_autogain; - sd->autogain = 0; - break; - case 0x6024: /* SN9C102 */ - case 0x6025: /* SN9C102 */ - sd->sensor = SENSOR_TAS5130CXX; - break; - case 0x6028: /* SN9C102 */ - sd->sensor = SENSOR_PAS202; - break; - case 0x602d: /* SN9C102 */ - sd->sensor = SENSOR_HV7131R; - break; - case 0x60af: /* SN9C103 */ - sd->sensor = SENSOR_PAS202; - sd->fr_h_sz = 18; /* size of frame header (?) */ - break; - } -/* break; */ -/* } */ + /* copy the webcam info from the device id */ + sd->sensor = (id->driver_info >> 24) & 0xff; + if (id->driver_info & (F_GAIN << 16)) + sd->sensor_has_gain = 1; + if (id->driver_info & (F_AUTO << 16)) + sd->sd_desc.dq_callback = do_autogain; + if (id->driver_info & (F_SIF << 16)) + sif = 1; + if (id->driver_info & (F_H18 << 16)) + sd->fr_h_sz = 18; /* size of frame header */ + else + sd->fr_h_sz = 12; + sd->sd_desc.nctrls = (id->driver_info >> 8) & 0xff; + sd->sensor_addr = id->driver_info & 0xff; cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; if (!sif) { cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); - if (sd->sensor == SENSOR_OV7630_3) { - /* We only have 320x240 & 640x480 */ - cam->cam_mode++; - cam->nmodes--; - } } else { cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); @@ -993,12 +823,9 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->brightness = BRIGHTNESS_DEF; sd->gain = GAIN_DEF; sd->exposure = EXPOSURE_DEF; + sd->autogain = AUTOGAIN_DEF; sd->freq = FREQ_DEF; - sd->contrast = CONTRAST_DEF; - sd->saturation = SATURATION_DEF; - sd->hue = HUE_DEF; - if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */ - reg_w(gspca_dev, 0x01, probe_ov7630, sizeof probe_ov7630); + return 0; } @@ -1032,9 +859,8 @@ static void pas106_i2cinit(struct gspca_dev *gspca_dev) static void sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int mode, l; + int mode, l = 0x1f; const __u8 *sn9c10x; - __u8 reg01, reg17; __u8 reg17_19[3]; mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; @@ -1052,13 +878,11 @@ static void sd_start(struct gspca_dev *gspca_dev) reg17_19[2] = 0x20; break; case SENSOR_OV7630: - sn9c10x = initOv7630; - reg17_19[0] = 0x68; - reg17_19[1] = (mode << 4) | COMP2; - reg17_19[2] = MCK_INIT1; - break; - case SENSOR_OV7630_3: - sn9c10x = initOv7630_3; + if (sd->fr_h_sz == 18) { /* SN9C103 */ + sn9c10x = initOv7630_3; + l = sizeof initOv7630_3; + } else + sn9c10x = initOv7630; reg17_19[0] = 0x68; reg17_19[1] = (mode << 4) | COMP2; reg17_19[2] = MCK_INIT1; @@ -1089,30 +913,11 @@ static void sd_start(struct gspca_dev *gspca_dev) reg17_19[2] = mode ? 0x23 : 0x43; break; } - switch (sd->sensor) { - case SENSOR_OV7630: - reg01 = 0x06; - reg17 = 0x29; - l = sizeof initOv7630; - break; - case SENSOR_OV7630_3: - reg01 = 0x44; - reg17 = 0x68; - l = sizeof initOv7630_3; - break; - default: - reg01 = sn9c10x[0]; - reg17 = sn9c10x[0x17 - 1]; - l = 0x1f; - break; - } /* reg 0x01 bit 2 video transfert on */ - reg_w(gspca_dev, 0x01, ®01, 1); + reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1); /* reg 0x17 SensorClk enable inv Clk 0x60 */ - reg_w(gspca_dev, 0x17, ®17, 1); -/*fixme: for ov7630 102 - reg_w(gspca_dev, 0x01, {0x06, sn9c10x[1]}, 2); */ + reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1); /* Set the registers from the template */ reg_w_big(gspca_dev, 0x01, sn9c10x, l); switch (sd->sensor) { @@ -1125,17 +930,13 @@ static void sd_start(struct gspca_dev *gspca_dev) sizeof ov6650_sensor_init); break; case SENSOR_OV7630: - i2c_w_vector(gspca_dev, ov7630_sensor_init_com, - sizeof ov7630_sensor_init_com); - msleep(200); i2c_w_vector(gspca_dev, ov7630_sensor_init, sizeof ov7630_sensor_init); - break; - case SENSOR_OV7630_3: - i2c_w_vector(gspca_dev, ov7630_sensor_init_com, - sizeof ov7630_sensor_init_com); - msleep(200); - i2c_w(gspca_dev, ov7630_sensor_init_3[mode]); + if (sd->fr_h_sz == 18) { /* SN9C103 */ + const __u8 i2c[] = { 0xa0, 0x21, 0x13, 0x80, 0x00, + 0x00, 0x00, 0x10 }; + i2c_w(gspca_dev, i2c); + } break; case SENSOR_PAS106: pas106_i2cinit(gspca_dev); @@ -1175,14 +976,14 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x18, ®17_19[1], 2); msleep(20); + sd->reg11 = -1; + setgain(gspca_dev); setbrightness(gspca_dev); setexposure(gspca_dev); setfreq(gspca_dev); - setsaturation(gspca_dev); - sethue(gspca_dev); - setcontrast(gspca_dev); + sd->frames_to_drop = 0; sd->autogain_ignore_frames = 0; atomic_set(&sd->avg_lum, -1); } @@ -1228,21 +1029,31 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, && data[3 + i] == 0xc4 && data[4 + i] == 0xc4 && data[5 + i] == 0x96) { /* start of frame */ - frame = gspca_frame_add(gspca_dev, LAST_PACKET, - frame, data, 0); + int lum = -1; + int pkt_type = LAST_PACKET; + if (len - i < sd->fr_h_sz) { - atomic_set(&sd->avg_lum, -1); PDEBUG(D_STREAM, "packet too short to" " get avg brightness"); } else if (sd->fr_h_sz == 12) { - atomic_set(&sd->avg_lum, - data[i + 8] + - (data[i + 9] << 8)); + lum = data[i + 8] + (data[i + 9] << 8); } else { - atomic_set(&sd->avg_lum, - data[i + 9] + - (data[i + 10] << 8)); + lum = data[i + 9] + + (data[i + 10] << 8); + } + if (lum == 0) { + lum = -1; + sd->frames_to_drop = 2; } + atomic_set(&sd->avg_lum, lum); + + if (sd->frames_to_drop) { + sd->frames_to_drop--; + pkt_type = DISCARD_PACKET; + } + + frame = gspca_frame_add(gspca_dev, pkt_type, + frame, data, 0); data += i + sd->fr_h_sz; len -= i + sd->fr_h_sz; gspca_frame_add(gspca_dev, FIRST_PACKET, @@ -1357,60 +1168,6 @@ static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->saturation = val; - if (gspca_dev->streaming) - setsaturation(gspca_dev); - return 0; -} - -static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->saturation; - return 0; -} - -static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hue = val; - if (gspca_dev->streaming) - sethue(gspca_dev); - return 0; -} - -static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hue; - return 0; -} - -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return 0; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { @@ -1448,27 +1205,47 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name +#define SFCI(sensor, flags, nctrls, i2c_addr) \ + .driver_info = (SENSOR_ ## sensor << 24) \ + | ((flags) << 16) \ + | ((nctrls) << 8) \ + | (i2c_addr) static __devinitdata struct usb_device_id device_table[] = { #ifndef CONFIG_USB_SN9C102 - {USB_DEVICE(0x0c45, 0x6001), DVNM("Genius VideoCAM NB")}, - {USB_DEVICE(0x0c45, 0x6005), DVNM("Sweex Tas5110")}, - {USB_DEVICE(0x0c45, 0x6007), DVNM("Sonix sn9c101 + Tas5110D")}, - {USB_DEVICE(0x0c45, 0x6009), DVNM("spcaCam@120")}, - {USB_DEVICE(0x0c45, 0x600d), DVNM("spcaCam@120")}, + {USB_DEVICE(0x0c45, 0x6001), /* SN9C102 */ + SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)}, + {USB_DEVICE(0x0c45, 0x6005), /* SN9C101 */ + SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)}, + {USB_DEVICE(0x0c45, 0x6007), /* SN9C101 */ + SFCI(TAS5110, F_GAIN|F_AUTO|F_SIF, 4, 0)}, + {USB_DEVICE(0x0c45, 0x6009), /* SN9C101 */ + SFCI(PAS106, F_SIF, 2, 0)}, + {USB_DEVICE(0x0c45, 0x600d), /* SN9C101 */ + SFCI(PAS106, F_SIF, 2, 0)}, #endif - {USB_DEVICE(0x0c45, 0x6011), DVNM("MAX Webcam Microdia")}, + {USB_DEVICE(0x0c45, 0x6011), /* SN9C101 - SN9C101G */ + SFCI(OV6650, F_GAIN|F_AUTO|F_SIF, 5, 0x60)}, #ifndef CONFIG_USB_SN9C102 - {USB_DEVICE(0x0c45, 0x6019), DVNM("Generic Sonix OV7630")}, - {USB_DEVICE(0x0c45, 0x6024), DVNM("Generic Sonix Tas5130c")}, - {USB_DEVICE(0x0c45, 0x6025), DVNM("Xcam Shanga")}, - {USB_DEVICE(0x0c45, 0x6028), DVNM("Sonix Btc Pc380")}, - {USB_DEVICE(0x0c45, 0x6029), DVNM("spcaCam@150")}, - {USB_DEVICE(0x0c45, 0x602c), DVNM("Generic Sonix OV7630")}, - {USB_DEVICE(0x0c45, 0x602d), DVNM("LIC-200 LG")}, - {USB_DEVICE(0x0c45, 0x602e), DVNM("Genius VideoCam Messenger")}, - {USB_DEVICE(0x0c45, 0x60af), DVNM("Trust WB3100P")}, - {USB_DEVICE(0x0c45, 0x60b0), DVNM("Genius VideoCam Look")}, + {USB_DEVICE(0x0c45, 0x6019), /* SN9C101 */ + SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)}, + {USB_DEVICE(0x0c45, 0x6024), /* SN9C102 */ + SFCI(TAS5130CXX, 0, 2, 0)}, + {USB_DEVICE(0x0c45, 0x6025), /* SN9C102 */ + SFCI(TAS5130CXX, 0, 2, 0)}, + {USB_DEVICE(0x0c45, 0x6028), /* SN9C102 */ + SFCI(PAS202, 0, 2, 0)}, + {USB_DEVICE(0x0c45, 0x6029), /* SN9C101 */ + SFCI(PAS106, F_SIF, 2, 0)}, + {USB_DEVICE(0x0c45, 0x602c), /* SN9C102 */ + SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)}, + {USB_DEVICE(0x0c45, 0x602d), /* SN9C102 */ + SFCI(HV7131R, 0, 2, 0)}, + {USB_DEVICE(0x0c45, 0x602e), /* SN9C102 */ + SFCI(OV7630, F_GAIN|F_AUTO, 5, 0x21)}, + {USB_DEVICE(0x0c45, 0x60af), /* SN9C103 */ + SFCI(PAS202, F_H18, 2, 0)}, + {USB_DEVICE(0x0c45, 0x60b0), /* SN9C103 */ + SFCI(OV7630, F_GAIN|F_AUTO|F_H18, 5, 0x21)}, #endif {} }; @@ -1487,6 +1264,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index 5d16f16f0..217a31a0e 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -32,7 +32,7 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int avg_lum; + atomic_t avg_lum; unsigned int exposure; unsigned short brightness; @@ -54,8 +54,10 @@ struct sd { #define SENSOR_HV7131R 0 #define SENSOR_MI0360 1 #define SENSOR_MO4000 2 -#define SENSOR_OV7648 3 -#define SENSOR_OV7660 4 +#define SENSOR_OM6802 3 +#define SENSOR_OV7630 4 +#define SENSOR_OV7648 5 +#define SENSOR_OV7660 6 unsigned char i2c_base; }; @@ -76,7 +78,8 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Brightness", .minimum = 0, - .maximum = 0xffff, +#define BRIGHTNESS_MAX 0xffff + .maximum = BRIGHTNESS_MAX, .step = 1, #define BRIGHTNESS_DEF 0x7fff .default_value = BRIGHTNESS_DEF, @@ -90,7 +93,8 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Contrast", .minimum = 0, - .maximum = 127, +#define CONTRAST_MAX 127 + .maximum = CONTRAST_MAX, .step = 1, #define CONTRAST_DEF 63 .default_value = CONTRAST_DEF, @@ -104,9 +108,9 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Color", .minimum = 0, - .maximum = 255, + .maximum = 64, .step = 1, -#define COLOR_DEF 127 +#define COLOR_DEF 32 .default_value = COLOR_DEF, }, .set = sd_setcolors, @@ -131,7 +135,7 @@ static struct ctrl sd_ctrls[] = { static struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 8 + 590, + .sizeimage = 160 * 120 * 4 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 2}, {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, @@ -148,65 +152,94 @@ static struct v4l2_pix_format vga_mode[] = { /*Data from sn9c102p+hv71331r */ static const __u8 sn_hv7131[] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */ - 0x00, 0x03, 0x64, 0x00, 0x1A, 0x20, 0x20, 0x20, 0xA1, 0x11, -/* rega regb regc regd rege regf reg10 reg11 */ - 0x02, 0x09, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, /* 00 */ -/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */ - 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, 0x0a, 0x00, 0x00, 0x00, -/* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x03, 0x64, 0x00, 0x1a, 0x20, 0x20, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0xa1, 0x11, 0x02, 0x09, 0x00, 0x00, 0x00, 0x10, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x01, 0x03, 0x28, 0x1e, 0x41, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const __u8 sn_mi0360[] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 reg9 */ - 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xb1, 0x5d, -/* rega regb regc regd rege regf reg10 reg11 */ - 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, -/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a reg1b */ - 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, 0x06, 0x00, 0x00, 0x00, -/* reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0xb1, 0x5d, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x61, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const __u8 sn_mo4000[] = { -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */ - 0x12, 0x23, 0x60, 0x00, 0x1A, 0x00, 0x20, 0x18, 0x81, -/* reg9 rega regb regc regd rege regf reg10 reg11*/ - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, -/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/ - 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40, 0x08, 0x00, 0x00, -/* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x25, 0x39, 0x4b, - 0x5c, 0x6b, 0x79, 0x87, 0x95, 0xa2, 0xaf, 0xbb, 0xc7, - 0xd3, 0xdf, 0xea, 0xf5 +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x12, 0x23, 0x60, 0x00, 0x1a, 0x00, 0x20, 0x18, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x0b, 0x0f, 0x14, 0x28, 0x1e, 0x40, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static const __u8 sn_om6802[] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x23, 0x72, 0x00, 0x1a, 0x34, 0x27, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x80, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x51, 0x01, 0x00, 0x28, 0x1e, 0x40, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x22, 0x44, 0x63, 0x7d, 0x92, 0xa3, 0xaf, + 0xbc, 0xc4, 0xcd, 0xd5, 0xdc, 0xe1, 0xe8, 0xef, + 0xf7 +}; + +static const __u8 sn_ov7630[] = { +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x21, 0x40, 0x00, 0x1a, 0x20, 0x1f, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0xa1, 0x21, 0x76, 0x21, 0x00, 0x00, 0x00, 0x10, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x04, 0x01, 0x0a, 0x28, 0x1e, 0xc2, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const __u8 sn_ov7648[] = { - 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, 0xA1, 0x6E, 0x18, 0x65, - 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1E, 0x82, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x21, 0x62, 0x00, 0x1a, 0x20, 0x20, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0xa1, 0x6e, 0x18, 0x65, 0x00, 0x00, 0x00, 0x10, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x00, 0x06, 0x06, 0x28, 0x1e, 0x82, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 }; static const __u8 sn_ov7660[] = { -# if 1 /*jfm: from win trace */ -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */ - 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x81, -/* reg9 rega regb regc regd rege regf reg10 reg11*/ - 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, -/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/ - 0x01, 0x01, 0x14, 0x28, 0x1e, 0x00, 0x07, 0x00, 0x00, -/* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +#if 0 +/*jfm: from win trace */ +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x01, 0x01, 0x14, 0x28, 0x1e, 0x00, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, #else -/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 reg8 */ - 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x81, -/* reg9 rega regb regc regd rege regf reg10 reg11*/ - 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, 0x03, 0x00, -/* reg12 reg13 reg14 reg15 reg16 reg17 reg18 reg19 reg1a*/ - 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20, 0x07, 0x00, 0x00, -/* reg1b reg1c reg1d reg1e reg1f reg20 reg21 reg22 reg23*/ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */ + 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20, +/* reg8 reg9 rega regb regc regd rege regf */ + 0x81, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10, +/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */ + 0x03, 0x00, 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20, +/* reg18 reg19 reg1a reg1b reg1c reg1d reg1e reg1f */ + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, #endif }; @@ -215,50 +248,26 @@ static const __u8 *sn_tb[] = { sn_hv7131, sn_mi0360, sn_mo4000, + sn_om6802, + sn_ov7630, sn_ov7648, sn_ov7660 }; -static const __u8 regsn20[] = { +static const __u8 gamma_def[] = { 0x00, 0x2d, 0x46, 0x5a, 0x6c, 0x7c, 0x8b, 0x99, 0xa6, 0xb2, 0xbf, 0xca, 0xd5, 0xe0, 0xeb, 0xf5, 0xff }; -static const __u8 regsn20_sn9c120[] = { - 0x00, 0x25, 0x3c, 0x50, 0x62, 0x72, 0x81, 0x90, - 0x9e, 0xab, 0xb8, 0xc5, 0xd1, 0xdd, 0xe9, 0xf4, 0xff -}; -static const __u8 regsn20_sn9c325[] = { - 0x0a, 0x3a, 0x56, 0x6c, 0x7e, 0x8d, 0x9a, 0xa4, - 0xaf, 0xbb, 0xc5, 0xcd, 0xd5, 0xde, 0xe8, 0xed, 0xf5 -}; static const __u8 reg84[] = { 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe5, 0x0f, 0xe4, 0x0f, 0x38, 0x00, 0x3e, 0x00, 0xc3, 0x0f, -/* 0x00, 0x00, 0x00, 0x00, 0x00 */ +#if 1 + 0xf7, 0x0f, 0x00, 0x00, 0x00 +#else 0xf7, 0x0f, 0x0a, 0x00, 0x00 +#endif }; -static const __u8 reg84_sn9c120_1[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0c, 0x00, 0x00 -}; -static const __u8 reg84_sn9c120_2[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x0c, 0x02, 0x3b -}; -static const __u8 reg84_sn9c120_3[] = { - 0x14, 0x00, 0x27, 0x00, 0x08, 0x00, 0xeb, 0x0f, - 0xd5, 0x0f, 0x42, 0x00, 0x41, 0x00, 0xca, 0x0f, - 0xf5, 0x0f, 0x0c, 0x02, 0x3b -}; -static const __u8 reg84_sn9c325[] = { - 0x14, 0x00, 0x27, 0x00, 0x07, 0x00, 0xe4, 0x0f, - 0xd3, 0x0f, 0x4b, 0x00, 0x48, 0x00, 0xc0, 0x0f, - 0xf8, 0x0f, 0x00, 0x00, 0x00 -}; - static const __u8 hv7131r_sensor_init[][8] = { {0xC1, 0x11, 0x01, 0x08, 0x01, 0x00, 0x00, 0x10}, {0xB1, 0x11, 0x34, 0x17, 0x7F, 0x00, 0x00, 0x10}, @@ -367,21 +376,105 @@ static const __u8 mo4000_sensor_init[][8] = { {0xa1, 0x21, 0x11, 0x38, 0x00, 0x00, 0x00, 0x10}, {} }; +static __u8 om6802_sensor_init[][8] = { + {0xa0, 0x34, 0x90, 0x05, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0x49, 0x85, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0x5a, 0xc0, 0x00, 0x00, 0x00, 0x10}, + {0xa0, 0x34, 0xdd, 0x18, 0x00, 0x00, 0x00, 0x10}, +/* {0xa0, 0x34, 0xfb, 0x11, 0x00, 0x00, 0x00, 0x10}, */ + {0xa0, 0x34, 0xf0, 0x04, 0x00, 0x00, 0x00, 0x10}, + /* white balance & auto-exposure */ +/* {0xa0, 0x34, 0xf1, 0x02, 0x00, 0x00, 0x00, 0x10}, + * set color mode */ +/* {0xa0, 0x34, 0xfe, 0x5b, 0x00, 0x00, 0x00, 0x10}, + * max AGC value in AE */ +/* {0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset AGC */ +/* {0xa0, 0x34, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset brightness */ +/* {0xa0, 0x34, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x10}, + * preset contrast */ +/* {0xa0, 0x34, 0xe8, 0x31, 0x00, 0x00, 0x00, 0x10}, + * preset gamma */ + {0xa0, 0x34, 0xe9, 0x0f, 0x00, 0x00, 0x00, 0x10}, + /* luminance mode (0x4f = AE) */ + {0xa0, 0x34, 0xe4, 0xff, 0x00, 0x00, 0x00, 0x10}, + /* preset shutter */ +/* {0xa0, 0x34, 0xef, 0x00, 0x00, 0x00, 0x00, 0x10}, + * auto frame rate */ +/* {0xa0, 0x34, 0xfb, 0xee, 0x00, 0x00, 0x00, 0x10}, */ + +/* {0xa0, 0x34, 0x71, 0x84, 0x00, 0x00, 0x00, 0x10}, */ +/* {0xa0, 0x34, 0x72, 0x05, 0x00, 0x00, 0x00, 0x10}, */ +/* {0xa0, 0x34, 0x68, 0x80, 0x00, 0x00, 0x00, 0x10}, */ +/* {0xa0, 0x34, 0x69, 0x01, 0x00, 0x00, 0x00, 0x10}, */ + {} +}; +static const __u8 ov7630_sensor_init[][8] = { + {0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10}, +/* win: delay 20ms */ + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10}, +/* win: delay 20ms */ + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, +/* win: i2c_r from 00 to 80 */ + {0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10}, + {0xb1, 0x21, 0x0c, 0x20, 0x20, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x11, 0x00, 0x48, 0xc0, 0x00, 0x10}, + {0xb1, 0x21, 0x15, 0x80, 0x03, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10}, + {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x1f, 0x00, 0x80, 0x80, 0x80, 0x10}, + {0xd1, 0x21, 0x23, 0xde, 0x10, 0x8a, 0xa0, 0x10}, + {0xc1, 0x21, 0x27, 0xca, 0xa2, 0x74, 0x00, 0x10}, + {0xd1, 0x21, 0x2a, 0x88, 0x00, 0x88, 0x01, 0x10}, + {0xc1, 0x21, 0x2e, 0x80, 0x00, 0x18, 0x00, 0x10}, + {0xa1, 0x21, 0x21, 0x08, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x32, 0xc2, 0x08, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x60, 0x05, 0x40, 0x12, 0x57, 0x10}, + {0xa1, 0x21, 0x64, 0x73, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x65, 0x00, 0x55, 0x01, 0xac, 0x10}, + {0xa1, 0x21, 0x69, 0x38, 0x00, 0x00, 0x00, 0x10}, + {0xd1, 0x21, 0x6f, 0x1f, 0x01, 0x00, 0x10, 0x10}, + {0xd1, 0x21, 0x73, 0x50, 0x20, 0x02, 0x01, 0x10}, + {0xd1, 0x21, 0x77, 0xf3, 0x90, 0x98, 0x98, 0x10}, + {0xc1, 0x21, 0x7b, 0x00, 0x4c, 0xf7, 0x00, 0x10}, + {0xd1, 0x21, 0x17, 0x1b, 0xbd, 0x05, 0xf6, 0x10}, + {0xa1, 0x21, 0x1b, 0x04, 0x00, 0x00, 0x00, 0x10}, +/* */ + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10}, +/*fixme: + 0x12, 0x04*/ + {0xa1, 0x21, 0x75, 0x82, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x32, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x01, 0x80, 0x80, 0x00, 0x00, 0x10}, +/* */ + {0xa1, 0x21, 0x11, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2a, 0x88, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10}, +/* */ + {0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, + {} +}; static const __u8 ov7660_sensor_init[][8] = { {0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */ /* (delay 20ms) */ {0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10}, - /* Outformat ?? rawRGB */ + /* Outformat = rawRGB */ {0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */ - {0xd1, 0x21, 0x00, 0x01, 0x74, 0x92, 0x00, 0x10}, -/* {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10}, */ + {0xd1, 0x21, 0x00, 0x01, 0x74, 0x74, 0x00, 0x10}, /* GAIN BLUE RED VREF */ {0xd1, 0x21, 0x04, 0x00, 0x7d, 0x62, 0x00, 0x10}, /* COM 1 BAVE GEAVE AECHH */ {0xb1, 0x21, 0x08, 0x83, 0x01, 0x00, 0x00, 0x10}, /* RAVE COM2 */ {0xd1, 0x21, 0x0c, 0x00, 0x08, 0x04, 0x4f, 0x10}, /* COM 3 4 5 6 */ - {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xf8, 0x10}, -/* {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10}, */ + {0xd1, 0x21, 0x10, 0x7f, 0x40, 0x05, 0xff, 0x10}, /* AECH CLKRC COM7 COM8 */ {0xc1, 0x21, 0x14, 0x2c, 0x00, 0x02, 0x00, 0x10}, /* COM9 COM10 */ {0xd1, 0x21, 0x17, 0x10, 0x60, 0x02, 0x7b, 0x10}, @@ -390,8 +483,8 @@ static const __u8 ov7660_sensor_init[][8] = { {0xb1, 0x21, 0x1e, 0x01, 0x0e, 0x00, 0x00, 0x10}, /* MVFP LAEC */ {0xd1, 0x21, 0x20, 0x07, 0x07, 0x07, 0x07, 0x10}, /* BOS GBOS GROS ROS (BGGR offset) */ - {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10}, -/* {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10}, */ +/* {0xd1, 0x21, 0x24, 0x68, 0x58, 0xd4, 0x80, 0x10}, */ + {0xd1, 0x21, 0x24, 0x78, 0x68, 0xd4, 0x80, 0x10}, /* AEW AEB VPT BBIAS */ {0xd1, 0x21, 0x28, 0x80, 0x30, 0x00, 0x00, 0x10}, /* GbBIAS RSVD EXHCH EXHCL */ @@ -418,9 +511,9 @@ static const __u8 ov7660_sensor_init[][8] = { {0xd1, 0x21, 0x62, 0x00, 0x00, 0x50, 0x30, 0x10}, /* LCC1 LCC2 LCC3 LCC4 */ {0xa1, 0x21, 0x66, 0x00, 0x00, 0x00, 0x00, 0x10}, /* LCC5 */ - {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10}, + {0xd1, 0x21, 0x67, 0x80, 0x7a, 0x90, 0x80, 0x10}, /* MANU */ {0xa1, 0x21, 0x6b, 0x0a, 0x00, 0x00, 0x00, 0x10}, - /* band gap reference [0..3] DBLV */ + /* band gap reference [0:3] DBLV */ {0xd1, 0x21, 0x6c, 0x30, 0x48, 0x80, 0x74, 0x10}, /* gamma curve */ {0xd1, 0x21, 0x70, 0x64, 0x60, 0x5c, 0x58, 0x10}, /* gamma curve */ {0xd1, 0x21, 0x74, 0x54, 0x4c, 0x40, 0x38, 0x10}, /* gamma curve */ @@ -430,37 +523,35 @@ static const __u8 ov7660_sensor_init[][8] = { {0xd1, 0x21, 0x84, 0x6e, 0x77, 0x87, 0x95, 0x10}, /* gamma curve */ {0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */ {0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */ - {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, + {0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */ /****** (some exchanges in the win trace) ******/ - {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */ /* bits[3..0]reserved */ {0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, /* VREF vertical frame ctrl */ {0xa1, 0x21, 0x03, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* 0x20 */ - {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, -/* {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, */ - {0xa1, 0x21, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x10, 0x20, 0x00, 0x00, 0x00, 0x10}, /* AECH 0x20 */ + {0xa1, 0x21, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFL */ + {0xa1, 0x21, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x10}, /* ADVFH */ + {0xa1, 0x21, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x10}, /* GAIN */ +/* {0xb1, 0x21, 0x01, 0x78, 0x78, 0x00, 0x00, 0x10}, * BLUE */ /****** (some exchanges in the win trace) ******/ {0xa1, 0x21, 0x93, 0x00, 0x00, 0x00, 0x00, 0x10},/* dummy line hight */ - {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10},/* dummy line low */ - {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, - {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, + {0xa1, 0x21, 0x92, 0x25, 0x00, 0x00, 0x00, 0x10}, /* dummy line low */ + {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCH */ + {0xa1, 0x21, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x10}, /* EXHCL */ +/* {0xa1, 0x21, 0x02, 0x90, 0x00, 0x00, 0x00, 0x10}, * RED */ /****** (some exchanges in the win trace) ******/ -/**********startsensor KO if changed !!****/ +/******!! startsensor KO if changed !!****/ {0xa1, 0x21, 0x93, 0x01, 0x00, 0x00, 0x00, 0x10}, {0xa1, 0x21, 0x92, 0xff, 0x00, 0x00, 0x00, 0x10}, {0xa1, 0x21, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x10}, {0xa1, 0x21, 0x2b, 0xc3, 0x00, 0x00, 0x00, 0x10}, -/* here may start the isoc exchanges */ {} }; -/* reg0x04 reg0x07 reg 0x10 */ -/* expo = (COM1 & 0x02) | (AECHH & 0x2f <<10) [ (AECh << 2) */ +/* reg 0x04 reg 0x07 reg 0x10 */ +/* expo = (COM1 & 0x02) | ((AECHH & 0x2f) << 10) | (AECh << 2) */ static const __u8 ov7648_sensor_init[][8] = { {0xC1, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00}, @@ -691,13 +782,16 @@ static int configure_gpio(struct gspca_dev *gspca_dev, const __u8 *reg9a; static const __u8 reg9a_def[] = {0x08, 0x40, 0x20, 0x10, 0x00, 0x04}; - static const __u8 reg9a_sn9c120[] = /* from win trace */ - {0x00, 0x40, 0x38, 0x30, 0x00, 0x20}; static const __u8 reg9a_sn9c325[] = {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20}; + static const __u8 regd4[] = {0x60, 0x00, 0x00}; reg_w1(gspca_dev, 0xf1, 0x00); - reg_w1(gspca_dev, 0x01, sn9c1xx[0]); /*fixme:jfm was [1] en v1*/ +#if 1 + reg_w1(gspca_dev, 0x01, sn9c1xx[1]); +#else + reg_w1(gspca_dev, 0x01, 0x00); /*jfm: in some win traces*/ +#endif /* configure gpio */ reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2); @@ -707,39 +801,54 @@ static int configure_gpio(struct gspca_dev *gspca_dev, case BRIDGE_SN9C325: reg9a = reg9a_sn9c325; break; - case BRIDGE_SN9C120: - reg9a = reg9a_sn9c120; - break; default: reg9a = reg9a_def; break; } reg_w(gspca_dev, 0x9a, reg9a, 6); - reg_w1(gspca_dev, 0xd4, 0x60); /*fixme:jfm 60 00 00 (3) ? */ + reg_w(gspca_dev, 0xd4, regd4, sizeof regd4); /*fixme:jfm was 60 only*/ reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f); - switch (sd->bridge) { - case BRIDGE_SN9C120: /* from win trace */ + switch (sd->sensor) { + case SENSOR_OM6802: + reg_w1(gspca_dev, 0x02, 0x71); + reg_w1(gspca_dev, 0x01, 0x42); + reg_w1(gspca_dev, 0x17, 0x64); + reg_w1(gspca_dev, 0x01, 0x42); + break; +#if 1 +/*jfm: from win trace */ + case SENSOR_OV7630: reg_w1(gspca_dev, 0x01, 0x61); - reg_w1(gspca_dev, 0x17, 0x20); + reg_w1(gspca_dev, 0x17, 0xe2); reg_w1(gspca_dev, 0x01, 0x60); + reg_w1(gspca_dev, 0x01, 0x40); break; - case BRIDGE_SN9C325: +#endif + case SENSOR_OV7648: reg_w1(gspca_dev, 0x01, 0x43); reg_w1(gspca_dev, 0x17, 0xae); reg_w1(gspca_dev, 0x01, 0x42); break; +#if 0 +/*jfm: from win trace */ + case SENSOR_OV7660: + reg_w1(gspca_dev, 0x01, 0x61); + reg_w1(gspca_dev, 0x17, 0x20); + reg_w1(gspca_dev, 0x01, 0x60); + break; +#endif default: reg_w1(gspca_dev, 0x01, 0x43); reg_w1(gspca_dev, 0x17, 0x61); reg_w1(gspca_dev, 0x01, 0x42); - } - - if (sd->sensor == SENSOR_HV7131R) { - if (probesensor(gspca_dev) < 0) - return -ENODEV; + if (sd->sensor == SENSOR_HV7131R) { + if (probesensor(gspca_dev) < 0) + return -ENODEV; + } + break; } return 0; } @@ -777,6 +886,40 @@ static void mo4000_InitSensor(struct gspca_dev *gspca_dev) } } +static void om6802_InitSensor(struct gspca_dev *gspca_dev) +{ + int i = 0; + + while (om6802_sensor_init[i][0]) { + i2c_w8(gspca_dev, om6802_sensor_init[i]); + i++; + } +} + +static void ov7630_InitSensor(struct gspca_dev *gspca_dev) +{ + int i = 0; + + i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 76 01 */ + i++; + i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 c8 (RGB+SRST) */ + i++; + msleep(20); + i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 48 */ + i++; + i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 c8 */ + i++; + msleep(20); + i2c_w8(gspca_dev, ov7630_sensor_init[i]); /* 12 48 */ + i++; +/*jfm:win i2c_r from 00 to 80*/ + + while (ov7630_sensor_init[i][0]) { + i2c_w8(gspca_dev, ov7630_sensor_init[i]); + i++; + } +} + static void ov7648_InitSensor(struct gspca_dev *gspca_dev) { int i = 0; @@ -806,197 +949,23 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 product; - - product = id->idProduct; - sd->sensor = -1; - switch (id->idVendor) { - case 0x0458: /* Genius */ -/* switch (product) { - case 0x7025: */ - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_MI0360; - sd->i2c_base = 0x5d; -/* break; - } */ - break; - case 0x045e: -/* switch (product) { - case 0x00f5: - case 0x00f7: */ - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_OV7660; - sd->i2c_base = 0x21; -/* break; - } */ - break; - case 0x0471: /* Philips */ -/* switch (product) { - case 0x0327: - case 0x0328: - case 0x0330: */ - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_MI0360; - sd->i2c_base = 0x5d; -/* break; - } */ - break; - case 0x0c45: /* Sonix */ - switch (product) { - case 0x6040: - sd->bridge = BRIDGE_SN9C102P; -/* sd->sensor = SENSOR_MI0360; * from BW600.inf */ -/*fixme: MI0360 base=5d ? */ - sd->sensor = SENSOR_HV7131R; /* gspcav1 value */ - sd->i2c_base = 0x11; - break; -/* case 0x607a: * from BW600.inf - sd->bridge = BRIDGE_SN9C102P; - sd->sensor = SENSOR_OV7648; - sd->i2c_base = 0x??; - break; */ - case 0x607c: - sd->bridge = BRIDGE_SN9C102P; - sd->sensor = SENSOR_HV7131R; - sd->i2c_base = 0x11; - break; -/* case 0x607e: * from BW600.inf - sd->bridge = BRIDGE_SN9C102P; - sd->sensor = SENSOR_OV7630; - sd->i2c_base = 0x??; - break; */ - case 0x60c0: - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_MI0360; - sd->i2c_base = 0x5d; - break; -/* case 0x60c8: * from BW600.inf - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_OM6801; - sd->i2c_base = 0x??; - break; */ -/* case 0x60cc: * from BW600.inf - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_HV7131GP; - sd->i2c_base = 0x??; - break; */ - case 0x60ec: - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_MO4000; - sd->i2c_base = 0x21; - break; -/* case 0x60ef: * from BW600.inf - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_ICM105C; - sd->i2c_base = 0x??; - break; */ -/* case 0x60fa: * from BW600.inf - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_OV7648; - sd->i2c_base = 0x??; - break; */ - case 0x60fb: - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_OV7660; - sd->i2c_base = 0x21; - break; - case 0x60fc: - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_HV7131R; - sd->i2c_base = 0x11; - break; -/* case 0x60fe: * from BW600.inf - sd->bridge = BRIDGE_SN9C105; - sd->sensor = SENSOR_OV7630; - sd->i2c_base = 0x??; - break; */ -/* case 0x6108: * from BW600.inf - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_OM6801; - sd->i2c_base = 0x??; - break; */ -/* case 0x6122: * from BW600.inf - sd->bridge = BRIDGE_SN9C110; - sd->sensor = SENSOR_ICM105C; - sd->i2c_base = 0x??; - break; */ - case 0x612a: -/* sd->bridge = BRIDGE_SN9C110; * in BW600.inf */ - sd->bridge = BRIDGE_SN9C325; - sd->sensor = SENSOR_OV7648; - sd->i2c_base = 0x21; -/*fixme: sensor_init has base = 00 et 6e!*/ - break; -/* case 0x6123: * from BW600.inf - sd->bridge = BRIDGE_SN9C110; - sd->sensor = SENSOR_SanyoCCD; - sd->i2c_base = 0x??; - break; */ - case 0x612c: - sd->bridge = BRIDGE_SN9C110; - sd->sensor = SENSOR_MO4000; - sd->i2c_base = 0x21; - break; -/* case 0x612e: * from BW600.inf - sd->bridge = BRIDGE_SN9C110; - sd->sensor = SENSOR_OV7630; - sd->i2c_base = 0x??; - break; */ -/* case 0x612f: * from BW600.inf - sd->bridge = BRIDGE_SN9C110; - sd->sensor = SENSOR_ICM105C; - sd->i2c_base = 0x??; - break; */ - case 0x6130: - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_MI0360; - sd->i2c_base = 0x5d; - break; - case 0x6138: - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_MO4000; - sd->i2c_base = 0x21; - break; -/* case 0x613a: * from BW600.inf - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_OV7648; - sd->i2c_base = 0x??; - break; */ - case 0x613b: - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_OV7660; - sd->i2c_base = 0x21; - break; - case 0x613c: - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_HV7131R; - sd->i2c_base = 0x11; - break; -/* case 0x613e: * from BW600.inf - sd->bridge = BRIDGE_SN9C120; - sd->sensor = SENSOR_OV7630; - sd->i2c_base = 0x??; - break; */ - } - break; - } - if (sd->sensor < 0) { - PDEBUG(D_ERR, "Invalid vendor/product %04x:%04x", - id->idVendor, product); - return -EINVAL; - } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); + sd->bridge = id->driver_info >> 16; + sd->sensor = id->driver_info >> 8; + sd->i2c_base = id->driver_info; + sd->qindex = 4; /* set the quantization table */ sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; sd->colors = COLOR_DEF; sd->autogain = AUTOGAIN_DEF; + sd->ag_cnt = -1; + return 0; } @@ -1010,10 +979,11 @@ static int sd_open(struct gspca_dev *gspca_dev) /* setup a selector by bridge */ reg_w1(gspca_dev, 0xf1, 0x01); - reg_r(gspca_dev, 0x00, 1); /* -> regF1 = 0x00 */ - reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]); reg_r(gspca_dev, 0x00, 1); + reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]); + reg_r(gspca_dev, 0x00, 1); /* get sonix chip id */ regF1 = gspca_dev->usb_buf[0]; + PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1); switch (sd->bridge) { case BRIDGE_SN9C102P: if (regF1 != 0x11) @@ -1109,16 +1079,53 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev, | ((expoMo10[3] & 0x30) >> 4)); break; } + case SENSOR_OM6802: { + __u8 gainOm[] = + { 0xa0, 0x34, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x10 }; + + if (expo > 0x03ff) + expo = 0x03ff; + if (expo < 0x0001) + expo = 0x0001; + gainOm[3] = expo >> 2; + i2c_w8(gspca_dev, gainOm); + reg_w1(gspca_dev, 0x96, (expo >> 5) & 0x1f); + PDEBUG(D_CONF, "set exposure %d", gainOm[3]); + break; + } } return expo; } +/* this function is used for sensors o76xx only */ +static void setbrightcont(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + unsigned val; + __u8 reg84_full[13]; + + memset(reg84_full, 0, sizeof reg84_full); + val = sd->contrast * 0x20 / CONTRAST_MAX + 0x10; /* 10..30 */ + reg84_full[2] = val; + reg84_full[0] = (val + 1) / 2; + reg84_full[4] = (val + 1) / 5; + if (val > BRIGHTNESS_DEF) + val = (sd->brightness - BRIGHTNESS_DEF) * 0x20 + / BRIGHTNESS_MAX; + else + val = 0; + reg84_full[10] = val; /* 00..1f */ + reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full); +} + +/* sensor != ov76xx */ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; unsigned int expo; __u8 k2; + k2 = sd->brightness >> 10; switch (sd->sensor) { case SENSOR_HV7131R: expo = sd->brightness << 4; @@ -1129,29 +1136,27 @@ static void setbrightness(struct gspca_dev *gspca_dev) sd->exposure = setexposure(gspca_dev, expo); break; case SENSOR_MI0360: + case SENSOR_MO4000: expo = sd->brightness >> 4; sd->exposure = setexposure(gspca_dev, expo); break; - case SENSOR_MO4000: - expo = sd->brightness >> 4; + case SENSOR_OM6802: + expo = sd->brightness >> 6; sd->exposure = setexposure(gspca_dev, expo); + k2 = sd->brightness >> 11; break; - case SENSOR_OV7660: - return; /*jfm??*/ } - k2 = sd->brightness >> 10; reg_w1(gspca_dev, 0x96, k2); } +/* sensor != ov76xx */ static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u8 k2; __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 }; - if (sd->sensor == SENSOR_OV7660) - return; /*jfm??*/ k2 = sd->contrast; contrast[2] = k2; contrast[0] = (k2 + 1) >> 1; @@ -1162,15 +1167,34 @@ static void setcontrast(struct gspca_dev *gspca_dev) static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - __u8 data; - int colour; + __u8 blue, red; - colour = sd->colors - 128; - if (colour > 0) - data = (colour + 32) & 0x7f; /* blue */ - else - data = (-colour + 32) & 0x7f; /* red */ - reg_w1(gspca_dev, 0x05, data); + if (sd->colors >= 32) { + red = 32 + (sd->colors - 32) / 2; + blue = 64 - sd->colors; + } else { + red = sd->colors; + blue = 32 + (32 - sd->colors) / 2; + } + reg_w1(gspca_dev, 0x05, red); +/* reg_w1(gspca_dev, 0x07, 32); */ + reg_w1(gspca_dev, 0x06, blue); +} + +static void setautogain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + switch (sd->sensor) { + case SENSOR_HV7131R: + case SENSOR_MO4000: + case SENSOR_MI0360: + if (sd->autogain) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; + break; + } } /* -- start the camera -- */ @@ -1178,25 +1202,19 @@ static void sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int i; - __u8 data; - __u8 reg1; - __u8 reg17; + __u8 reg1, reg17, reg18; const __u8 *sn9c1xx; int mode; static const __u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f }; static const __u8 CA[] = { 0x28, 0xd8, 0x14, 0xec }; - static const __u8 CA_sn9c120[] = - { 0x14, 0xec, 0x0a, 0xf6 }; /* SN9C120 */ static const __u8 CE[] = { 0x32, 0xdd, 0x2d, 0xdd }; /* MI0360 */ - static const __u8 CE_sn9c325[] = - { 0x32, 0xdd, 0x32, 0xdd }; /* OV7648 - SN9C325 */ + static const __u8 CE_ov76xx[] = + { 0x32, 0xdd, 0x32, 0xdd }; /* OV7630/48 */ sn9c1xx = sn_tb[(int) sd->sensor]; configure_gpio(gspca_dev, sn9c1xx); -/*fixme:jfm this sequence should appear at end of sd_start */ -/* with - reg_w1(gspca_dev, 0x01, 0x44); */ +/* reg_w1(gspca_dev, 0x01, 0x44); jfm from win trace*/ reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]); reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]); reg_w1(gspca_dev, 0x12, sn9c1xx[0x12]); @@ -1208,56 +1226,46 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0xc7, 0x00); reg_w1(gspca_dev, 0xc8, 0x50); reg_w1(gspca_dev, 0xc9, 0x3c); -/*fixme:jfm end of ending sequence */ reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]); - switch (sd->bridge) { - case BRIDGE_SN9C325: - data = 0xae; + switch (sd->sensor) { + case SENSOR_OV7630: + reg17 = 0xe2; break; - case BRIDGE_SN9C120: - data = 0xa0; + case SENSOR_OV7648: + reg17 = 0xae; + break; +#if 1 +/*jfm: from win trace */ + case SENSOR_OV7660: + reg17 = 0xa0; break; +#endif default: - data = 0x60; + reg17 = 0x60; break; } - reg_w1(gspca_dev, 0x17, data); + reg_w1(gspca_dev, 0x17, reg17); reg_w1(gspca_dev, 0x05, sn9c1xx[5]); reg_w1(gspca_dev, 0x07, sn9c1xx[7]); reg_w1(gspca_dev, 0x06, sn9c1xx[6]); reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]); + reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def); + for (i = 0; i < 8; i++) + reg_w(gspca_dev, 0x84, reg84, sizeof reg84); +#if 0 switch (sd->bridge) { case BRIDGE_SN9C325: - reg_w(gspca_dev, 0x20, regsn20_sn9c325, - sizeof regsn20_sn9c325); - for (i = 0; i < 8; i++) - reg_w(gspca_dev, 0x84, reg84_sn9c325, - sizeof reg84_sn9c325); reg_w1(gspca_dev, 0x9a, 0x0a); reg_w1(gspca_dev, 0x99, 0x60); break; - case BRIDGE_SN9C120: - reg_w(gspca_dev, 0x20, regsn20_sn9c120, - sizeof regsn20_sn9c120); - for (i = 0; i < 2; i++) - reg_w(gspca_dev, 0x84, reg84_sn9c120_1, - sizeof reg84_sn9c120_1); - for (i = 0; i < 6; i++) - reg_w(gspca_dev, 0x84, reg84_sn9c120_2, - sizeof reg84_sn9c120_2); - reg_w(gspca_dev, 0x84, reg84_sn9c120_3, - sizeof reg84_sn9c120_3); - reg_w1(gspca_dev, 0x9a, 0x05); - reg_w1(gspca_dev, 0x99, 0x5b); - break; default: - reg_w(gspca_dev, 0x20, regsn20, sizeof regsn20); - for (i = 0; i < 8; i++) - reg_w(gspca_dev, 0x84, reg84, sizeof reg84); +#endif reg_w1(gspca_dev, 0x9a, 0x08); reg_w1(gspca_dev, 0x99, 0x59); +#if 0 break; } +#endif mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; if (mode) @@ -1282,6 +1290,15 @@ static void sd_start(struct gspca_dev *gspca_dev) /* reg1 = 0x06; * 640 clk 24Mz (done) */ } break; + case SENSOR_OM6802: + om6802_InitSensor(gspca_dev); + reg17 = 0x64; /* 640 MCKSIZE */ + break; + case SENSOR_OV7630: + ov7630_InitSensor(gspca_dev); + reg17 = 0xe2; + reg1 = 0x44; + break; case SENSOR_OV7648: ov7648_InitSensor(gspca_dev); reg17 = 0xa2; @@ -1299,7 +1316,8 @@ static void sd_start(struct gspca_dev *gspca_dev) /* reg1 = 0x44; */ /* reg1 = 0x46; (done) */ } else { -#if 1 +#if 0 +/*jfm: from win trace */ reg17 = 0xa2; /* 640 */ reg1 = 0x40; #else @@ -1310,18 +1328,11 @@ static void sd_start(struct gspca_dev *gspca_dev) break; } reg_w(gspca_dev, 0xc0, C0, 6); - switch (sd->bridge) { - case BRIDGE_SN9C120: /*jfm ?? */ - reg_w(gspca_dev, 0xca, CA_sn9c120, 4); - break; - default: - reg_w(gspca_dev, 0xca, CA, 4); - break; - } - switch (sd->bridge) { - case BRIDGE_SN9C120: /*jfm ?? */ - case BRIDGE_SN9C325: - reg_w(gspca_dev, 0xce, CE_sn9c325, 4); + reg_w(gspca_dev, 0xca, CA, 4); + switch (sd->sensor) { + case SENSOR_OV7630: + case SENSOR_OV7648: + reg_w(gspca_dev, 0xce, CE_ov76xx, 4); break; default: reg_w(gspca_dev, 0xce, CE, 4); @@ -1330,19 +1341,29 @@ static void sd_start(struct gspca_dev *gspca_dev) } /* here change size mode 0 -> VGA; 1 -> CIF */ - data = 0x40 | sn9c1xx[0x18] | (mode << 4); - reg_w1(gspca_dev, 0x18, data); + reg18 = sn9c1xx[0x18] | (mode << 4); + reg_w1(gspca_dev, 0x18, reg18 | 0x40); reg_w(gspca_dev, 0x100, qtable4, 0x40); reg_w(gspca_dev, 0x140, qtable4 + 0x40, 0x40); - data = sn9c1xx[0x18] | (mode << 4); - reg_w1(gspca_dev, 0x18, data); + reg_w1(gspca_dev, 0x18, reg18); reg_w1(gspca_dev, 0x17, reg17); reg_w1(gspca_dev, 0x01, reg1); - setbrightness(gspca_dev); - setcontrast(gspca_dev); + switch (sd->sensor) { + case SENSOR_HV7131R: + case SENSOR_MI0360: + case SENSOR_MO4000: + case SENSOR_OM6802: + setbrightness(gspca_dev); + setcontrast(gspca_dev); + break; + default: /* OV76xx */ + setbrightcont(gspca_dev); + break; + } + setautogain(gspca_dev); } static void sd_stopN(struct gspca_dev *gspca_dev) @@ -1365,12 +1386,12 @@ static void sd_stopN(struct gspca_dev *gspca_dev) i2c_w8(gspca_dev, stopmi0360); data = 0x29; break; - case SENSOR_MO4000: - break; + case SENSOR_OV7630: case SENSOR_OV7648: data = 0x29; break; default: +/* case SENSOR_MO4000: */ /* case SENSOR_OV7660: */ break; } @@ -1379,7 +1400,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]); reg_w1(gspca_dev, 0x01, sn9c1xx[1]); reg_w1(gspca_dev, 0x01, data); - reg_w1(gspca_dev, 0xf1, 0x01); + reg_w1(gspca_dev, 0xf1, 0x00); } static void sd_stop0(struct gspca_dev *gspca_dev) @@ -1390,16 +1411,23 @@ static void sd_close(struct gspca_dev *gspca_dev) { } -static void setautogain(struct gspca_dev *gspca_dev) +static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - /* Thanks S., without your advice, autobright should not work :) */ int delta; - int expotimes = 0; + int expotimes; __u8 luma_mean = 130; __u8 luma_delta = 20; - delta = sd->avg_lum; + /* Thanks S., without your advice, autobright should not work :) */ + if (sd->ag_cnt < 0) + return; + if (--sd->ag_cnt >= 0) + return; + sd->ag_cnt = AG_CNT_START; + + delta = atomic_read(&sd->avg_lum); + PDEBUG(D_FRAM, "mean lum %d", delta); if (delta < luma_mean - luma_delta || delta > luma_mean + luma_delta) { switch (sd->sensor) { @@ -1411,8 +1439,10 @@ static void setautogain(struct gspca_dev *gspca_dev) sd->exposure = setexposure(gspca_dev, (unsigned int) (expotimes << 8)); break; - case SENSOR_MO4000: - case SENSOR_MI0360: + default: +/* case SENSOR_MO4000: */ +/* case SENSOR_MI0360: */ +/* case SENSOR_OM6802: */ expotimes = sd->exposure; expotimes += (luma_mean - delta) >> 6; if (expotimes < 0) @@ -1425,6 +1455,8 @@ static void setautogain(struct gspca_dev *gspca_dev) } } +/* scan the URB packets */ +/* This function is run at interrupt level. */ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -1441,9 +1473,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, frame, data, sof + 2); if (sd->ag_cnt < 0) return; - if (--sd->ag_cnt >= 0) - return; - sd->ag_cnt = AG_CNT_START; /* w1 w2 w3 */ /* w4 w5 w6 */ /* w7 w8 */ @@ -1458,9 +1487,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* w5 */ avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4; avg_lum >>= 4; - sd->avg_lum = avg_lum; - PDEBUG(D_PACK, "mean lum %d", avg_lum); - setautogain(gspca_dev); + atomic_set(&sd->avg_lum, avg_lum); return; } if (gspca_dev->last_packet_type == LAST_PACKET) { @@ -1471,70 +1498,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } -static unsigned int getexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 hexpo, mexpo, lexpo; - - switch (sd->sensor) { - case SENSOR_HV7131R: - /* read sensor exposure */ - i2c_r5(gspca_dev, 0x25); - return (gspca_dev->usb_buf[0] << 16) - | (gspca_dev->usb_buf[1] << 8) - | gspca_dev->usb_buf[2]; - case SENSOR_MI0360: - /* read sensor exposure */ - i2c_r5(gspca_dev, 0x09); - return (gspca_dev->usb_buf[0] << 8) - | gspca_dev->usb_buf[1]; - case SENSOR_MO4000: - i2c_r5(gspca_dev, 0x0e); - hexpo = 0; /* gspca_dev->usb_buf[1] & 0x07; */ - mexpo = 0x40; /* gspca_dev->usb_buf[2] & 0xff; */ - lexpo = (gspca_dev->usb_buf[1] & 0x30) >> 4; - PDEBUG(D_CONF, "exposure %d", - (hexpo << 10) | (mexpo << 2) | lexpo); - return (hexpo << 10) | (mexpo << 2) | lexpo; - default: -/* case SENSOR_OV7660: */ - /* read sensor exposure */ - i2c_r5(gspca_dev, 0x04); - hexpo = gspca_dev->usb_buf[3] & 0x2f; - lexpo = gspca_dev->usb_buf[0] & 0x02; - i2c_r5(gspca_dev, 0x08); - mexpo = gspca_dev->usb_buf[2]; - return (hexpo << 10) | (mexpo << 2) | lexpo; - } -} - -static void getbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* hardcoded registers seem not readable */ - switch (sd->sensor) { - case SENSOR_HV7131R: -/* sd->brightness = 0x7fff; */ - sd->brightness = getexposure(gspca_dev) >> 4; - break; - case SENSOR_MI0360: - sd->brightness = getexposure(gspca_dev) << 4; - break; - case SENSOR_MO4000: -/* sd->brightness = 0x1fff; */ - sd->brightness = getexposure(gspca_dev) << 4; - break; - } -} - static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); + if (gspca_dev->streaming) { + switch (sd->sensor) { + case SENSOR_HV7131R: + case SENSOR_MI0360: + case SENSOR_MO4000: + case SENSOR_OM6802: + setbrightness(gspca_dev); + break; + default: /* OV76xx */ + setbrightcont(gspca_dev); + break; + } + } return 0; } @@ -1542,7 +1523,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - getbrightness(gspca_dev); *val = sd->brightness; return 0; } @@ -1552,8 +1532,19 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); + if (gspca_dev->streaming) { + switch (sd->sensor) { + case SENSOR_HV7131R: + case SENSOR_MI0360: + case SENSOR_MO4000: + case SENSOR_OM6802: + setcontrast(gspca_dev); + break; + default: /* OV76xx */ + setbrightcont(gspca_dev); + break; + } + } return 0; } @@ -1588,10 +1579,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->autogain = val; - if (val) - sd->ag_cnt = AG_CNT_START; - else - sd->ag_cnt = -1; + if (gspca_dev->streaming) + setautogain(gspca_dev); return 0; } @@ -1615,33 +1604,57 @@ static const struct sd_desc sd_desc = { .stop0 = sd_stop0, .close = sd_close, .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name +#define BSI(bridge, sensor, i2c_addr) \ + .driver_info = (BRIDGE_ ## bridge << 16) \ + | (SENSOR_ ## sensor << 8) \ + | (i2c_addr) static const __devinitdata struct usb_device_id device_table[] = { #ifndef CONFIG_USB_SN9C102 - {USB_DEVICE(0x0458, 0x7025), DVNM("Genius Eye 311Q")}, - {USB_DEVICE(0x045e, 0x00f5), DVNM("MicroSoft VX3000")}, - {USB_DEVICE(0x045e, 0x00f7), DVNM("MicroSoft VX1000")}, - {USB_DEVICE(0x0471, 0x0327), DVNM("Philips SPC 600 NC")}, - {USB_DEVICE(0x0471, 0x0328), DVNM("Philips SPC 700 NC")}, + {USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)}, + {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)}, + {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)}, + {USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)}, + {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)}, #endif - {USB_DEVICE(0x0471, 0x0330), DVNM("Philips SPC 710NC")}, - {USB_DEVICE(0x0c45, 0x6040), DVNM("Speed NVC 350K")}, - {USB_DEVICE(0x0c45, 0x607c), DVNM("Sonix sn9c102p Hv7131R")}, - {USB_DEVICE(0x0c45, 0x60c0), DVNM("Sangha Sn535")}, - {USB_DEVICE(0x0c45, 0x60ec), DVNM("SN9C105+MO4000")}, - {USB_DEVICE(0x0c45, 0x60fb), DVNM("Surfer NoName")}, - {USB_DEVICE(0x0c45, 0x60fc), DVNM("LG-LIC300")}, - {USB_DEVICE(0x0c45, 0x612a), DVNM("Avant Camera")}, - {USB_DEVICE(0x0c45, 0x612c), DVNM("Typhoon Rasy Cam 1.3MPix")}, + {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)}, + {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)}, +/* bw600.inf: + {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */ +/* {USB_DEVICE(0x0c45, 0x603a), BSI(SN9C102P, OV7648, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x607a), BSI(SN9C102P, OV7648, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x607c), BSI(SN9C102P, HV7131R, 0x11)}, +/* {USB_DEVICE(0x0c45, 0x607e), BSI(SN9C102P, OV7630, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x60c0), BSI(SN9C105, MI0360, 0x5d)}, +/* {USB_DEVICE(0x0c45, 0x60c8), BSI(SN9C105, OM6801, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x60cc), BSI(SN9C105, HV7131GP, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x60ec), BSI(SN9C105, MO4000, 0x21)}, +/* {USB_DEVICE(0x0c45, 0x60ef), BSI(SN9C105, ICM105C, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x60fa), BSI(SN9C105, OV7648, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x60fb), BSI(SN9C105, OV7660, 0x21)}, + {USB_DEVICE(0x0c45, 0x60fc), BSI(SN9C105, HV7131R, 0x11)}, +/* {USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */ +/* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/ +/*bw600.inf:*/ + {USB_DEVICE(0x0c45, 0x612a), BSI(SN9C110, OV7648, 0x21)}, /*sn9c325?*/ + {USB_DEVICE(0x0c45, 0x612c), BSI(SN9C110, MO4000, 0x21)}, + {USB_DEVICE(0x0c45, 0x612e), BSI(SN9C110, OV7630, 0x21)}, +/* {USB_DEVICE(0x0c45, 0x612f), BSI(SN9C110, ICM105C, 0x??)}, */ #ifndef CONFIG_USB_SN9C102 - {USB_DEVICE(0x0c45, 0x6130), DVNM("Sonix Pccam")}, - {USB_DEVICE(0x0c45, 0x6138), DVNM("Sn9c120 Mo4000")}, - {USB_DEVICE(0x0c45, 0x613b), DVNM("Surfer SN-206")}, - {USB_DEVICE(0x0c45, 0x613c), DVNM("Sonix Pccam168")}, + {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)}, + {USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)}, +/* {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x??)}, */ + {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)}, + {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)}, +/* {USB_DEVICE(0x0c45, 0x613e), BSI(SN9C120, OV7630, 0x??)}, */ #endif + {USB_DEVICE(0x0c45, 0x6143), BSI(SN9C120, MI0360, 0x5d)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -1659,6 +1672,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/spca500.c b/linux/drivers/media/video/gspca/spca500.c index 81c5e091d..2aff5af9a 100644 --- a/linux/drivers/media/video/gspca/spca500.c +++ b/linux/drivers/media/video/gspca/spca500.c @@ -644,109 +644,10 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 vendor; - __u16 product; - - vendor = id->idVendor; - product = id->idProduct; - switch (vendor) { - case 0x040a: /* Kodak cameras */ -/* switch (product) { */ -/* case 0x0300: */ - sd->subtype = KodakEZ200; -/* break; */ -/* } */ - break; - case 0x041e: /* Creative cameras */ -/* switch (product) { */ -/* case 0x400a: */ - sd->subtype = CreativePCCam300; -/* break; */ -/* } */ - break; - case 0x046d: /* Logitech Labtec */ - switch (product) { - case 0x0890: - sd->subtype = LogitechTraveler; - break; - case 0x0900: - sd->subtype = LogitechClickSmart310; - break; - case 0x0901: - sd->subtype = LogitechClickSmart510; - break; - } - break; - case 0x04a5: /* Benq */ -/* switch (product) { */ -/* case 0x300c: */ - sd->subtype = BenqDC1016; -/* break; */ -/* } */ - break; - case 0x04fc: /* SunPlus */ -/* switch (product) { */ -/* case 0x7333: */ - sd->subtype = PalmPixDC85; -/* break; */ -/* } */ - break; - case 0x055f: /* Mustek cameras */ - switch (product) { - case 0xc200: - sd->subtype = MustekGsmart300; - break; - case 0xc220: - sd->subtype = Gsmartmini; - break; - } - break; - case 0x06bd: /* Agfa Cl20 */ -/* switch (product) { */ -/* case 0x0404: */ - sd->subtype = AgfaCl20; -/* break; */ -/* } */ - break; - case 0x06be: /* Optimedia */ -/* switch (product) { */ -/* case 0x0800: */ - sd->subtype = Optimedia; -/* break; */ -/* } */ - break; - case 0x084d: /* D-Link / Minton */ -/* switch (product) { */ -/* case 0x0003: * DSC-350 / S-Cam F5 */ - sd->subtype = DLinkDSC350; -/* break; */ -/* } */ - break; - case 0x08ca: /* Aiptek */ -/* switch (product) { */ -/* case 0x0103: */ - sd->subtype = AiptekPocketDV; -/* break; */ -/* } */ - break; - case 0x2899: /* ToptroIndustrial */ -/* switch (product) { */ -/* case 0x012c: */ - sd->subtype = ToptroIndus; -/* break; */ -/* } */ - break; - case 0x8086: /* Intel */ -/* switch (product) { */ -/* case 0x0630: * Pocket PC Camera */ - sd->subtype = IntelPocketPCCamera; -/* break; */ -/* } */ - break; - } + cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; + sd->subtype = id->driver_info; if (sd->subtype != LogitechClickSmart310) { cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; @@ -1176,23 +1077,22 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x040a, 0x0300), DVNM("Kodak EZ200")}, - {USB_DEVICE(0x041e, 0x400a), DVNM("Creative PC-CAM 300")}, - {USB_DEVICE(0x046d, 0x0890), DVNM("Logitech QuickCam traveler")}, - {USB_DEVICE(0x046d, 0x0900), DVNM("Logitech Inc. ClickSmart 310")}, - {USB_DEVICE(0x046d, 0x0901), DVNM("Logitech Inc. ClickSmart 510")}, - {USB_DEVICE(0x04a5, 0x300c), DVNM("Benq DC1016")}, - {USB_DEVICE(0x04fc, 0x7333), DVNM("PalmPixDC85")}, - {USB_DEVICE(0x055f, 0xc200), DVNM("Mustek Gsmart 300")}, - {USB_DEVICE(0x055f, 0xc220), DVNM("Gsmart Mini")}, - {USB_DEVICE(0x06bd, 0x0404), DVNM("Agfa CL20")}, - {USB_DEVICE(0x06be, 0x0800), DVNM("Optimedia")}, - {USB_DEVICE(0x084d, 0x0003), DVNM("D-Link DSC-350")}, - {USB_DEVICE(0x08ca, 0x0103), DVNM("Aiptek PocketDV")}, - {USB_DEVICE(0x2899, 0x012c), DVNM("Toptro Industrial")}, - {USB_DEVICE(0x8086, 0x0630), DVNM("Intel Pocket PC Camera")}, + {USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200}, + {USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300}, + {USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler}, + {USB_DEVICE(0x046d, 0x0900), .driver_info = LogitechClickSmart310}, + {USB_DEVICE(0x046d, 0x0901), .driver_info = LogitechClickSmart510}, + {USB_DEVICE(0x04a5, 0x300c), .driver_info = BenqDC1016}, + {USB_DEVICE(0x04fc, 0x7333), .driver_info = PalmPixDC85}, + {USB_DEVICE(0x055f, 0xc200), .driver_info = MustekGsmart300}, + {USB_DEVICE(0x055f, 0xc220), .driver_info = Gsmartmini}, + {USB_DEVICE(0x06bd, 0x0404), .driver_info = AgfaCl20}, + {USB_DEVICE(0x06be, 0x0800), .driver_info = Optimedia}, + {USB_DEVICE(0x084d, 0x0003), .driver_info = DLinkDSC350}, + {USB_DEVICE(0x08ca, 0x0103), .driver_info = AiptekPocketDV}, + {USB_DEVICE(0x2899, 0x012c), .driver_info = ToptroIndus}, + {USB_DEVICE(0x8086, 0x0630), .driver_info = IntelPocketPCCamera}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -1210,6 +1110,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/spca501.c b/linux/drivers/media/video/gspca/spca501.c index 10e90646d..df657cb9d 100644 --- a/linux/drivers/media/video/gspca/spca501.c +++ b/linux/drivers/media/video/gspca/spca501.c @@ -1931,63 +1931,12 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 vendor; - __u16 product; - - vendor = id->idVendor; - product = id->idProduct; - switch (vendor) { - case 0x0000: /* Unknow Camera */ -/* switch (product) { */ -/* case 0x0000: */ - sd->subtype = MystFromOriUnknownCamera; -/* break; */ -/* } */ - break; - case 0x040a: /* Kodak cameras */ -/* switch (product) { */ -/* case 0x0002: */ - sd->subtype = KodakDVC325; -/* break; */ -/* } */ - break; - case 0x0497: /* Smile International */ -/* switch (product) { */ -/* case 0xc001: */ - sd->subtype = SmileIntlCamera; -/* break; */ -/* } */ - break; - case 0x0506: /* 3COM cameras */ -/* switch (product) { */ -/* case 0x00df: */ - sd->subtype = ThreeComHomeConnectLite; -/* break; */ -/* } */ - break; - case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ - switch (product) { - case 0x0401: - sd->subtype = IntelCreateAndShare; - break; - case 0x0402: - sd->subtype = ViewQuestM318B; - break; - } - break; - case 0x1776: /* Arowana */ -/* switch (product) { */ -/* case 0x501c: */ - sd->subtype = Arowana300KCMOSCamera; -/* break; */ -/* } */ - break; - } + cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + sd->subtype = id->driver_info; sd->brightness = sd_ctrls[MY_BRIGHTNESS].qctrl.default_value; sd->contrast = sd_ctrls[MY_CONTRAST].qctrl.default_value; sd->colors = sd_ctrls[MY_COLOR].qctrl.default_value; @@ -2191,15 +2140,14 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x040a, 0x0002), DVNM("Kodak DVC-325")}, - {USB_DEVICE(0x0497, 0xc001), DVNM("Smile International")}, - {USB_DEVICE(0x0506, 0x00df), DVNM("3Com HomeConnect Lite")}, - {USB_DEVICE(0x0733, 0x0401), DVNM("Intel Create and Share")}, - {USB_DEVICE(0x0733, 0x0402), DVNM("ViewQuest M318B")}, - {USB_DEVICE(0x1776, 0x501c), DVNM("Arowana 300K CMOS Camera")}, - {USB_DEVICE(0x0000, 0x0000), DVNM("MystFromOri Unknow Camera")}, + {USB_DEVICE(0x040a, 0x0002), .driver_info = KodakDVC325}, + {USB_DEVICE(0x0497, 0xc001), .driver_info = SmileIntlCamera}, + {USB_DEVICE(0x0506, 0x00df), .driver_info = ThreeComHomeConnectLite}, + {USB_DEVICE(0x0733, 0x0401), .driver_info = IntelCreateAndShare}, + {USB_DEVICE(0x0733, 0x0402), .driver_info = ViewQuestM318B}, + {USB_DEVICE(0x1776, 0x501c), .driver_info = Arowana300KCMOSCamera}, + {USB_DEVICE(0x0000, 0x0000), .driver_info = MystFromOriUnknownCamera}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -2217,6 +2165,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/spca505.c b/linux/drivers/media/video/gspca/spca505.c index fc392b6d1..440e6853c 100644 --- a/linux/drivers/media/video/gspca/spca505.c +++ b/linux/drivers/media/video/gspca/spca505.c @@ -31,10 +31,6 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int buflen; - unsigned char tmpbuf[640 * 480 * 3 / 2]; /* YYUV per line */ - unsigned char tmpbuf2[640 * 480 * 2]; /* YUYV */ - unsigned char brightness; char subtype; @@ -64,29 +60,29 @@ static struct ctrl sd_ctrls[] = { }; static struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 160 * 2, - .sizeimage = 160 * 120 * 2, + {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 5}, - {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 176 * 2, - .sizeimage = 176 * 144 * 2, + {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 4}, - {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 320 * 2, - .sizeimage = 320 * 240 * 2, + {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 2}, - {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 352 * 2, - .sizeimage = 352 * 288 * 2, + {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, - {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 640 * 2, - .sizeimage = 640 * 480 * 2, + {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; @@ -707,33 +703,11 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 vendor; - __u16 product; - - vendor = id->idVendor; - product = id->idProduct; - switch (vendor) { - case 0x041e: /* Creative cameras */ -/* switch (product) { */ -/* case 0x401d: * here505b */ - sd->subtype = Nxultra; -/* break; */ -/* } */ - break; - case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ -/* switch (product) { */ -/* case 0x0430: */ -/* fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */ - sd->subtype = IntelPCCameraPro; -/* break; */ -/* } */ - break; - } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; + sd->subtype = id->driver_info; if (sd->subtype != IntelPCCameraPro) cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; else /* no 640x480 for IntelPCCameraPro */ @@ -851,77 +825,30 @@ static void sd_close(struct gspca_dev *gspca_dev) reg_write(gspca_dev->dev, 0x05, 0x11, 0xf); } -/* convert YYUV per line to YUYV (YUV 4:2:2) */ -static void yyuv_decode(unsigned char *out, - unsigned char *in, - int width, - int height) -{ - unsigned char *Ui, *Vi, *yi, *yi1; - unsigned char *out1; - int i, j; - - yi = in; - for (i = height / 2; --i >= 0; ) { - out1 = out + width * 2; /* next line */ - yi1 = yi + width; - Ui = yi1 + width; - Vi = Ui + width / 2; - for (j = width / 2; --j >= 0; ) { - *out++ = 128 + *yi++; - *out++ = 128 + *Ui; - *out++ = 128 + *yi++; - *out++ = 128 + *Vi; - - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Ui++; - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Vi++; - } - yi += width * 2; - out = out1; - } -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ { - struct sd *sd = (struct sd *) gspca_dev; - switch (data[0]) { case 0: /* start of frame */ - if (gspca_dev->last_packet_type == FIRST_PACKET) { - yyuv_decode(sd->tmpbuf2, sd->tmpbuf, - gspca_dev->width, - gspca_dev->height); - frame = gspca_frame_add(gspca_dev, - LAST_PACKET, - frame, - sd->tmpbuf2, - gspca_dev->width - * gspca_dev->height - * 2); - } - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, - data, 0); + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); data += SPCA50X_OFFSET_DATA; len -= SPCA50X_OFFSET_DATA; - if (len > 0) - memcpy(sd->tmpbuf, data, len); - else - len = 0; - sd->buflen = len; - return; + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + break; case 0xff: /* drop */ /* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; + break; + default: + data += 1; + len -= 1; + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, len); + break; } - data += 1; - len -= 1; - memcpy(&sd->tmpbuf[sd->buflen], data, len); - sd->buflen += len; } static void setbrightness(struct gspca_dev *gspca_dev) @@ -976,10 +903,10 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x401d), DVNM("Creative Webcam NX ULTRA")}, - {USB_DEVICE(0x0733, 0x0430), DVNM("Intel PC Camera Pro")}, + {USB_DEVICE(0x041e, 0x401d), .driver_info = Nxultra}, + {USB_DEVICE(0x0733, 0x0430), .driver_info = IntelPCCameraPro}, +/*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */ {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -997,6 +924,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/spca506.c b/linux/drivers/media/video/gspca/spca506.c index 40e8541b2..ae772488c 100644 --- a/linux/drivers/media/video/gspca/spca506.c +++ b/linux/drivers/media/video/gspca/spca506.c @@ -33,10 +33,6 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int buflen; - __u8 tmpbuf[640 * 480 * 3]; /* YYUV per line */ - __u8 tmpbuf2[640 * 480 * 2]; /* YUYV */ - unsigned char brightness; unsigned char contrast; unsigned char colors; @@ -115,29 +111,29 @@ static struct ctrl sd_ctrls[] = { }; static struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 160 * 2, - .sizeimage = 160 * 120 * 2, + {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 5}, - {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 176 * 2, - .sizeimage = 176 * 144 * 2, + {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 4}, - {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 320 * 2, - .sizeimage = 320 * 240 * 2, + {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 2}, - {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 352 * 2, - .sizeimage = 352 * 288 * 2, + {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, - {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 640 * 2, - .sizeimage = 640 * 480 * 2, + {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, + .bytesperline = 640, + .sizeimage = 640 * 480 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; @@ -307,7 +303,6 @@ static int sd_config(struct gspca_dev *gspca_dev, struct cam *cam; cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; @@ -573,77 +568,30 @@ static void sd_close(struct gspca_dev *gspca_dev) { } -/* convert YYUV per line to YUYV (YUV 4:2:2) */ -static void yyuv_decode(unsigned char *out, - unsigned char *in, - int width, - int height) -{ - unsigned char *Ui, *Vi, *yi, *yi1; - unsigned char *out1; - int i, j; - - yi = in; - for (i = height / 2; --i >= 0; ) { - out1 = out + width * 2; /* next line */ - yi1 = yi + width; - Ui = yi1 + width; - Vi = Ui + width / 2; - for (j = width / 2; --j >= 0; ) { - *out++ = 128 + *yi++; - *out++ = 128 + *Ui; - *out++ = 128 + *yi++; - *out++ = 128 + *Vi; - - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Ui++; - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Vi++; - } - yi += width * 2; - out = out1; - } -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ { - struct sd *sd = (struct sd *) gspca_dev; - switch (data[0]) { case 0: /* start of frame */ - if (gspca_dev->last_packet_type == FIRST_PACKET) { - yyuv_decode(sd->tmpbuf2, sd->tmpbuf, - gspca_dev->width, - gspca_dev->height); - frame = gspca_frame_add(gspca_dev, - LAST_PACKET, - frame, - sd->tmpbuf2, - gspca_dev->width - * gspca_dev->height - * 2); - } - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, - data, 0); + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); data += SPCA50X_OFFSET_DATA; len -= SPCA50X_OFFSET_DATA; - if (len > 0) - memcpy(sd->tmpbuf, data, len); - else - len = 0; - sd->buflen = len; - return; + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + break; case 0xff: /* drop */ /* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; + break; + default: + data += 1; + len -= 1; + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, len); + break; } - data += 1; - len -= 1; - memcpy(&sd->tmpbuf[sd->buflen], data, len); - sd->buflen += len; } static void setbrightness(struct gspca_dev *gspca_dev) @@ -801,12 +749,12 @@ static struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x06e1, 0xa190), DVNM("ADS Instant VCD")}, -/* {USB_DEVICE(0x0733, 0x0430), DVNM("UsbGrabber PV321c")}, */ - {USB_DEVICE(0x0734, 0x043b), DVNM("3DeMon USB Capture aka")}, - {USB_DEVICE(0x99fa, 0x8988), DVNM("Grandtec V.cap")}, + {USB_DEVICE(0x06e1, 0xa190)}, +/*fixme: may be IntelPCCameraPro BRIDGE_SPCA505 + {USB_DEVICE(0x0733, 0x0430)}, */ + {USB_DEVICE(0x0734, 0x043b)}, + {USB_DEVICE(0x99fa, 0x8988)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -824,6 +772,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/spca508.c b/linux/drivers/media/video/gspca/spca508.c index a8d611eba..585468863 100644 --- a/linux/drivers/media/video/gspca/spca508.c +++ b/linux/drivers/media/video/gspca/spca508.c @@ -30,10 +30,6 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int buflen; - unsigned char tmpbuf[352 * 288 * 3 / 2]; /* YUVY per line */ - unsigned char tmpbuf2[352 * 288 * 2]; /* YUYV */ - unsigned char brightness; char subtype; @@ -67,24 +63,24 @@ static struct ctrl sd_ctrls[] = { }; static struct v4l2_pix_format sif_mode[] = { - {160, 120, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 160 * 2, - .sizeimage = 160 * 120 * 2, + {160, 120, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 3}, - {176, 144, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 176 * 2, - .sizeimage = 176 * 144 * 2, + {176, 144, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 2}, - {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 320 * 2, - .sizeimage = 320 * 240 * 2, + {320, 240, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, - {352, 288, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, - .bytesperline = 352 * 2, - .sizeimage = 352 * 288 * 2, + {352, 288, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288 * 3 / 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; @@ -1511,58 +1507,8 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - __u16 product; int data1, data2; - product = id->idProduct; - switch (id->idVendor) { - case 0x0130: /* Clone webcam */ -/* switch (product) { */ -/* case 0x0130: */ - sd->subtype = HamaUSBSightcam; /* same as Hama 0010 */ -/* break; */ -/* } */ - break; - case 0x041e: /* Creative cameras */ -/* switch (product) { */ -/* case 0x4018: */ - sd->subtype = CreativeVista; -/* break; */ -/* } */ - break; - case 0x0461: /* MicroInnovation */ -/* switch (product) { */ -/* case 0x0815: */ - sd->subtype = MicroInnovationIC200; -/* break; */ -/* } */ - break; - case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ -/* switch (product) { */ -/* case 0x110: */ - sd->subtype = ViewQuestVQ110; -/* break; */ -/* } */ - break; - case 0x0af9: /* Hama cameras */ - switch (product) { - case 0x0010: - sd->subtype = HamaUSBSightcam; - break; - case 0x0011: - sd->subtype = HamaUSBSightcam2; - break; - } - break; - case 0x8086: /* Intel */ -/* switch (product) { */ -/* case 0x0110: */ - sd->subtype = IntelEasyPCCamera; -/* break; */ -/* } */ - break; - } - /* Read from global register the USB product and vendor IDs, just to * prove that we can communicate with the device. This works, which * confirms at we are communicating properly and that the device @@ -1579,10 +1525,11 @@ static int sd_config(struct gspca_dev *gspca_dev, PDEBUG(D_PROBE, "Window 1 average luminance: %d", data1); cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); + + sd->subtype = id->driver_info; sd->brightness = BRIGHTNESS_DEF; switch (sd->subtype) { @@ -1654,77 +1601,30 @@ static void sd_close(struct gspca_dev *gspca_dev) { } -/* convert YUVY per line to YUYV (YUV 4:2:2) */ -static void yuvy_decode(unsigned char *out, - unsigned char *in, - int width, - int height) -{ - unsigned char *Ui, *Vi, *yi, *yi1; - unsigned char *out1; - int i, j; - - yi = in; - for (i = height / 2; --i >= 0; ) { - out1 = out + width * 2; /* next line */ - Ui = yi + width; - Vi = Ui + width / 2; - yi1 = Vi + width / 2; - for (j = width / 2; --j >= 0; ) { - *out++ = 128 + *yi++; - *out++ = 128 + *Ui; - *out++ = 128 + *yi++; - *out++ = 128 + *Vi; - - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Ui++; - *out1++ = 128 + *yi1++; - *out1++ = 128 + *Vi++; - } - yi += width * 2; - out = out1; - } -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ int len) /* iso packet length */ { - struct sd *sd = (struct sd *) gspca_dev; - switch (data[0]) { case 0: /* start of frame */ - if (gspca_dev->last_packet_type == FIRST_PACKET) { - yuvy_decode(sd->tmpbuf2, sd->tmpbuf, - gspca_dev->width, - gspca_dev->height); - frame = gspca_frame_add(gspca_dev, - LAST_PACKET, - frame, - sd->tmpbuf2, - gspca_dev->width - * gspca_dev->height - * 2); - } - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, - data, 0); + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + data, 0); data += SPCA508_OFFSET_DATA; len -= SPCA508_OFFSET_DATA; - if (len > 0) - memcpy(sd->tmpbuf, data, len); - else - len = 0; - sd->buflen = len; - return; + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + data, len); + break; case 0xff: /* drop */ /* gspca_dev->last_packet_type = DISCARD_PACKET; */ - return; + break; + default: + data += 1; + len -= 1; + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, len); + break; } - data += 1; - len -= 1; - memcpy(&sd->tmpbuf[sd->buflen], data, len); - sd->buflen += len; } static void setbrightness(struct gspca_dev *gspca_dev) @@ -1780,15 +1680,14 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x0130, 0x0130), DVNM("Clone Digital Webcam 11043")}, - {USB_DEVICE(0x041e, 0x4018), DVNM("Creative Webcam Vista (PD1100)")}, - {USB_DEVICE(0x0461, 0x0815), DVNM("Micro Innovation IC200")}, - {USB_DEVICE(0x0733, 0x0110), DVNM("ViewQuest VQ110")}, - {USB_DEVICE(0x0af9, 0x0010), DVNM("Hama USB Sightcam 100")}, - {USB_DEVICE(0x0af9, 0x0011), DVNM("Hama USB Sightcam 100")}, - {USB_DEVICE(0x8086, 0x0110), DVNM("Intel Easy PC Camera")}, + {USB_DEVICE(0x0130, 0x0130), .driver_info = HamaUSBSightcam}, + {USB_DEVICE(0x041e, 0x4018), .driver_info = CreativeVista}, + {USB_DEVICE(0x0461, 0x0815), .driver_info = MicroInnovationIC200}, + {USB_DEVICE(0x0733, 0x0110), .driver_info = ViewQuestVQ110}, + {USB_DEVICE(0x0af9, 0x0010), .driver_info = HamaUSBSightcam}, + {USB_DEVICE(0x0af9, 0x0011), .driver_info = HamaUSBSightcam2}, + {USB_DEVICE(0x8086, 0x0110), .driver_info = IntelEasyPCCamera}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -1806,6 +1705,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c index 85c37f396..d686b6bd7 100644 --- a/linux/drivers/media/video/gspca/spca561.c +++ b/linux/drivers/media/video/gspca/spca561.c @@ -32,68 +32,47 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - unsigned short contrast; - __u8 brightness; + __u16 contrast; /* rev72a only */ +#define CONTRAST_MIN 0x0000 +#define CONTRAST_DEF 0x2000 +#define CONTRAST_MAX 0x3fff + + __u16 exposure; /* rev12a only */ +#define EXPOSURE_MIN 0 +#define EXPOSURE_DEF 200 +#define EXPOSURE_MAX 762 + + __u8 brightness; /* rev72a only */ +#define BRIGHTNESS_MIN 0 +#define BRIGHTNESS_DEF 32 +#define BRIGHTNESS_MAX 63 + + __u8 white; /* rev12a only */ +#define WHITE_MIN 1 +#define WHITE_DEF 0x40 +#define WHITE_MAX 0x7f + __u8 autogain; +#define AUTOGAIN_MIN 0 +#define AUTOGAIN_DEF 1 +#define AUTOGAIN_MAX 1 + + __u8 gain; /* rev12a only */ +#define GAIN_MIN 0x0 +#define GAIN_DEF 0x24 +#define GAIN_MAX 0x24 + +#define EXPO12A_DEF 3 + __u8 expo12a; /* expo/gain? for rev 12a */ __u8 chip_revision; +#define Rev012A 0 +#define Rev072A 1 + signed char ag_cnt; #define AG_CNT_START 13 }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); - -static struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 63, - .step = 1, - .default_value = 32, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define SD_CONTRAST 1 - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 0x3fff, - .step = 1, - .default_value = 0x2000, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -#define SD_AUTOGAIN 2 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -}; - static struct v4l2_pix_format sif_mode[] = { {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, .bytesperline = 160, @@ -143,12 +122,8 @@ static struct v4l2_pix_format sif_mode[] = { #define SPCA561_INDEX_I2C_BASE 0x8800 #define SPCA561_SNAPBIT 0x20 #define SPCA561_SNAPCTRL 0x40 -enum { - Rev072A = 0, - Rev012A, -}; -static void reg_w_val(struct usb_device *dev, __u16 index, __u16 value) +static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) { int ret; @@ -198,12 +173,6 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, index, gspca_dev->usb_buf, len, 500); } -static void i2c_init(struct gspca_dev *gspca_dev, __u8 mode) -{ - reg_w_val(gspca_dev->dev, 0x92, 0x8804); - reg_w_val(gspca_dev->dev, mode, 0x8802); -} - static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg) { int retry = 60; @@ -212,9 +181,9 @@ static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg) DataLow = valeur; DataHight = valeur >> 8; - reg_w_val(gspca_dev->dev, reg, 0x8801); - reg_w_val(gspca_dev->dev, DataLow, 0x8805); - reg_w_val(gspca_dev->dev, DataHight, 0x8800); + reg_w_val(gspca_dev->dev, 0x8801, reg); + reg_w_val(gspca_dev->dev, 0x8805, DataLow); + reg_w_val(gspca_dev->dev, 0x8800, DataHight); while (retry--) { reg_r(gspca_dev, 0x8803, 1); if (!gspca_dev->usb_buf[0]) @@ -228,9 +197,9 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) __u8 value; __u8 vallsb; - reg_w_val(gspca_dev->dev, 0x92, 0x8804); - reg_w_val(gspca_dev->dev, reg, 0x8801); - reg_w_val(gspca_dev->dev, (mode | 0x01), 0x8802); + reg_w_val(gspca_dev->dev, 0x8804, 0x92); + reg_w_val(gspca_dev->dev, 0x8801, reg); + reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01)); while (retry--) { reg_r(gspca_dev, 0x8803, 1); if (!gspca_dev->usb_buf) @@ -438,10 +407,11 @@ static const __u16 spca561_init_data[][2] = { {0x0035, 0x8801}, /* 0x14 - set gain general */ {0x001f, 0x8805}, /* 0x14 */ {0x0000, 0x8800}, - {0x0030, 0x8112}, + {0x000e, 0x8112}, /* white balance - was 30 */ {} }; +#if 0 static void sensor_reset(struct gspca_dev *gspca_dev) { reg_w_val(gspca_dev->dev, 0x8631, 0xc8); @@ -449,10 +419,12 @@ static void sensor_reset(struct gspca_dev *gspca_dev) reg_w_val(gspca_dev->dev, 0x8112, 0x00); reg_w_val(gspca_dev->dev, 0x8114, 0x00); reg_w_val(gspca_dev->dev, 0x8118, 0x21); - i2c_init(gspca_dev, 0x14); - i2c_write(gspca_dev, 1, 0x0d); - i2c_write(gspca_dev, 0, 0x0d); + reg_w_val(gspca_dev->dev, 0x8804, 0x92); /* i2c init */ + reg_w_val(gspca_dev->dev, 0x8802, 0x14); + i2c_write(gspca_dev, 0x0001, 0x0d); + i2c_write(gspca_dev, 0x0000, 0x0d); } +#endif /******************** QC Express etch2 stuff ********************/ static const __u16 Pb100_1map8300[][2] = { @@ -462,9 +434,9 @@ static const __u16 Pb100_1map8300[][2] = { {0x8303, 0x0125}, /* image area */ {0x8304, 0x0169}, {0x8328, 0x000b}, - {0x833c, 0x0001}, + {0x833c, 0x0001}, /*fixme: win:07*/ - {0x832f, 0x0419}, + {0x832f, 0x1904}, /*fixme: was 0419*/ {0x8307, 0x00aa}, {0x8301, 0x0003}, {0x8302, 0x000e}, @@ -478,9 +450,10 @@ static const __u16 Pb100_2map8300[][2] = { }; static const __u16 spca561_161rev12A_data1[][2] = { - {0x21, 0x8118}, - {0x01, 0x8114}, - {0x00, 0x8112}, + {0x29, 0x8118}, /* white balance - was 21 */ + {0x08, 0x8114}, /* white balance - was 01 */ + {0x0e, 0x8112}, /* white balance - was 00 */ + {0x00, 0x8102}, /* white balance - new */ {0x92, 0x8804}, {0x04, 0x8802}, /* windows uses 08 */ {} @@ -505,14 +478,16 @@ static const __u16 spca561_161rev12A_data2[][2] = { {0xb0, 0x8603}, /* sensor gains */ + {0x07, 0x8601}, /* white balance - new */ + {0x07, 0x8602}, /* white balance - new */ {0x00, 0x8610}, /* *red */ {0x00, 0x8611}, /* 3f *green */ {0x00, 0x8612}, /* green *blue */ {0x00, 0x8613}, /* blue *green */ - {0x35, 0x8614}, /* green *red */ - {0x35, 0x8615}, /* 40 *green */ - {0x35, 0x8616}, /* 7a *blue */ - {0x35, 0x8617}, /* 40 *green */ + {0x43, 0x8614}, /* green *red - white balance - was 0x35 */ + {0x40, 0x8615}, /* 40 *green - white balance - was 0x35 */ + {0x71, 0x8616}, /* 7a *blue - white balance - was 0x35 */ + {0x40, 0x8617}, /* 40 *green - white balance - was 0x35 */ {0x0c, 0x8620}, /* 0c */ {0xc8, 0x8631}, /* c8 */ @@ -527,6 +502,7 @@ static const __u16 spca561_161rev12A_data2[][2] = { {0xdf, 0x863c}, /* df */ {0xf0, 0x8505}, {0x32, 0x850a}, +/* {0x99, 0x8700}, * - white balance - new (removed) */ {} }; @@ -545,9 +521,10 @@ static void sensor_mapwrite(struct gspca_dev *gspca_dev, } static void init_161rev12A(struct gspca_dev *gspca_dev) { - sensor_reset(gspca_dev); +/* sensor_reset(gspca_dev); (not in win) */ write_vector(gspca_dev, spca561_161rev12A_data1); sensor_mapwrite(gspca_dev, Pb100_1map8300); +/*fixme: should be in sd_start*/ write_vector(gspca_dev, spca561_161rev12A_data2); sensor_mapwrite(gspca_dev, Pb100_2map8300); } @@ -579,57 +556,35 @@ static int sd_config(struct gspca_dev *gspca_dev, PDEBUG(D_PROBE, "Bad vendor / product from device"); return -EINVAL; } - switch (product) { - case 0x0928: - case 0x0929: - case 0x092a: - case 0x092b: - case 0x092c: - case 0x092d: - case 0x092e: - case 0x092f: - case 0x403b: - sd->chip_revision = Rev012A; - break; - default: -/* case 0x0561: - case 0x0815: * ?? in spca508.c - case 0x401a: - case 0x7004: - case 0x7e50: - case 0xa001: - case 0xcdee: */ - sd->chip_revision = Rev072A; - break; - } + cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ cam->cam_mode = sif_mode; - cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; - sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value; - sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value; - sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value; + cam->nmodes = ARRAY_SIZE(sif_mode); + + sd->chip_revision = id->driver_info; + sd->brightness = BRIGHTNESS_DEF; + sd->contrast = CONTRAST_DEF; + sd->white = WHITE_DEF; + sd->exposure = EXPOSURE_DEF; + sd->autogain = AUTOGAIN_DEF; + sd->gain = GAIN_DEF; + sd->expo12a = EXPO12A_DEF; return 0; } /* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +static int sd_open_12a(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - switch (sd->chip_revision) { - case Rev072A: - PDEBUG(D_STREAM, "Chip revision id: 072a"); - write_vector(gspca_dev, spca561_init_data); - break; - default: -/* case Rev012A: */ - PDEBUG(D_STREAM, "Chip revision id: 012a"); - init_161rev12A(gspca_dev); - break; - } + PDEBUG(D_STREAM, "Chip revision: 012a"); + init_161rev12A(gspca_dev); + return 0; +} +static int sd_open_72a(struct gspca_dev *gspca_dev) +{ + PDEBUG(D_STREAM, "Chip revision: 072a"); + write_vector(gspca_dev, spca561_init_data); return 0; } @@ -638,25 +593,20 @@ static void setcontrast(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; __u8 lowb; - int expotimes; switch (sd->chip_revision) { case Rev072A: lowb = sd->contrast >> 8; - reg_w_val(dev, lowb, 0x8651); - reg_w_val(dev, lowb, 0x8652); - reg_w_val(dev, lowb, 0x8653); - reg_w_val(dev, lowb, 0x8654); + reg_w_val(dev, 0x8651, lowb); + reg_w_val(dev, 0x8652, lowb); + reg_w_val(dev, 0x8653, lowb); + reg_w_val(dev, 0x8654, lowb); break; - case Rev012A: { - __u8 Reg8391[] = - { 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00 }; - - /* Write camera sensor settings */ - expotimes = (sd->contrast >> 5) & 0x07ff; - Reg8391[0] = expotimes & 0xff; /* exposure */ - Reg8391[1] = 0x18 | (expotimes >> 8); - Reg8391[2] = sd->brightness; /* gain */ + default: { +/* case Rev012A: { */ + static const __u8 Reg8391[] = + { 0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00 }; + reg_w_buf(gspca_dev, 0x8391, Reg8391, 8); reg_w_buf(gspca_dev, 0x8390, Reg8391, 8); break; @@ -664,74 +614,139 @@ static void setcontrast(struct gspca_dev *gspca_dev) } } -static void sd_start(struct gspca_dev *gspca_dev) +/* rev12a only */ +static void setwhite(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u16 white; + __u8 reg8614, reg8616; + + white = sd->white; + /* try to emulate MS-win as possible */ + reg8616 = 0x90 - white * 5 / 8; + reg_w_val(gspca_dev->dev, 0x8616, reg8616); + reg8614 = 0x20 + white * 3 / 8; + reg_w_val(gspca_dev->dev, 0x8614, reg8614); +} + +/* rev 12a only */ +static void setexposure(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int expo; + __u8 data[2]; + + expo = sd->exposure + 0x20a8; /* from test */ + data[0] = expo; + data[1] = expo >> 8; + reg_w_buf(gspca_dev, 0x8309, data, 2); +} + +/* rev 12a only */ +static void setgain(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 data[2]; + + data[0] = sd->gain; + data[1] = 0; + reg_w_buf(gspca_dev, 0x8335, data, 2); +} + +static void setautogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + + if (sd->autogain) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; +} + +static void sd_start_12a(struct gspca_dev *gspca_dev) +{ struct usb_device *dev = gspca_dev->dev; int Clck; __u8 Reg8307[] = { 0xaa, 0x00 }; int mode; mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - switch (sd->chip_revision) { - case Rev072A: - switch (mode) { - default: -/* case 0: - case 1: */ - Clck = 0x25; - break; - case 2: - Clck = 0x22; - break; - case 3: - Clck = 0x21; - break; - } - reg_w_val(dev, 0x8500, mode); /* mode */ - reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ - reg_w_val(dev, 0x8112, 0x10 | 0x20); + switch (mode) { + case 0: + case 1: + Clck = 0x8a; + break; + case 2: + Clck = 0x85; break; default: -/* case Rev012A: */ - switch (mode) { - case 0: - case 1: - Clck = 0x8a; - break; - case 2: - Clck = 0x85; - break; - default: - Clck = 0x83; - break; - } - if (mode <= 1) { - /* Use compression on 320x240 and above */ - reg_w_val(dev, 0x8500, 0x10 | mode); - } else { - /* I couldn't get the compression to work below 320x240 - * Fortunately at these resolutions the bandwidth - * is sufficient to push raw frames at ~20fps */ - reg_w_val(dev, 0x8500, mode); - } /* -- qq@kuku.eu.org */ - reg_w_buf(gspca_dev, 0x8307, Reg8307, 2); - reg_w_val(gspca_dev->dev, 0x8700, Clck); - /* 0x8f 0x85 0x27 clock */ - reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); - reg_w_val(gspca_dev->dev, 0x850b, 0x03); - setcontrast(gspca_dev); + Clck = 0x83; + break; + } + if (mode <= 1) { + /* Use compression on 320x240 and above */ + reg_w_val(dev, 0x8500, 0x10 | mode); + } else { + /* I couldn't get the compression to work below 320x240 + * Fortunately at these resolutions the bandwidth + * is sufficient to push raw frames at ~20fps */ + reg_w_val(dev, 0x8500, mode); + } /* -- qq@kuku.eu.org */ + reg_w_buf(gspca_dev, 0x8307, Reg8307, 2); + reg_w_val(gspca_dev->dev, 0x8700, Clck); + /* 0x8f 0x85 0x27 clock */ + reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); + reg_w_val(gspca_dev->dev, 0x850b, 0x03); + setcontrast(gspca_dev); + setwhite(gspca_dev); + setautogain(gspca_dev); +} +static void sd_start_72a(struct gspca_dev *gspca_dev) +{ + struct usb_device *dev = gspca_dev->dev; + int Clck; + int mode; + + mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + switch (mode) { + default: +/* case 0: + case 1: */ + Clck = 0x25; + break; + case 2: + Clck = 0x22; + break; + case 3: + Clck = 0x21; break; } + reg_w_val(dev, 0x8500, mode); /* mode */ + reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ + reg_w_val(dev, 0x8112, 0x10 | 0x20); + setautogain(gspca_dev); } static void sd_stopN(struct gspca_dev *gspca_dev) { - reg_w_val(gspca_dev->dev, 0x8112, 0x20); + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->chip_revision == Rev012A) { + reg_w_val(gspca_dev->dev, 0x8112, 0x0e); + } else { + reg_w_val(gspca_dev->dev, 0x8112, 0x20); +/* reg_w_val(gspca_dev->dev, 0x8102, 0x00); ?? */ + } } static void sd_stop0(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->chip_revision == Rev012A) { + reg_w_val(gspca_dev->dev, 0x8118, 0x29); + reg_w_val(gspca_dev->dev, 0x8114, 0x08); + } } /* this function is called at close time */ @@ -740,17 +755,24 @@ static void sd_close(struct gspca_dev *gspca_dev) reg_w_val(gspca_dev->dev, 0x8114, 0); } -static void setautogain(struct gspca_dev *gspca_dev) +static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int expotimes = 0; - int pixelclk = 0; - int gainG = 0; + int expotimes; + int pixelclk; + int gainG; __u8 R, Gr, Gb, B; int y; __u8 luma_mean = 110; __u8 luma_delta = 20; __u8 spring = 4; + __u8 reg8339[2]; + + if (sd->ag_cnt < 0) + return; + if (--sd->ag_cnt >= 0) + return; + sd->ag_cnt = AG_CNT_START; switch (sd->chip_revision) { case Rev072A: @@ -799,13 +821,16 @@ static void setautogain(struct gspca_dev *gspca_dev) } break; case Rev012A: - /* sensor registers is access and memory mapped to 0x8300 */ - /* readind all 0x83xx block the sensor */ - /* - * The data from the header seem wrong where is the luma - * and chroma mean value - * at the moment set exposure in contrast set - */ + reg_r(gspca_dev, 0x8330, 2); + if (gspca_dev->usb_buf[1] > 0x08) { + reg8339[0] = ++sd->expo12a; + reg8339[1] = 0; + reg_w_buf(gspca_dev, 0x8339, reg8339, 2); + } else if (gspca_dev->usb_buf[1] < 0x02) { + reg8339[0] = --sd->expo12a; + reg8339[1] = 0; + reg_w_buf(gspca_dev, 0x8339, reg8339, 2); + } break; } } @@ -815,18 +840,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, __u8 *data, /* isoc packet */ int len) /* iso packet length */ { - struct sd *sd = (struct sd *) gspca_dev; - switch (data[0]) { case 0: /* start of frame */ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0); - if (sd->ag_cnt >= 0) { - if (--sd->ag_cnt < 0) { - sd->ag_cnt = AG_CNT_START; - setautogain(gspca_dev); - } - } data += SPCA561_OFFSET_DATA; len -= SPCA561_OFFSET_DATA; if (data[1] & 0x10) { @@ -850,24 +867,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } +/* rev 72a only */ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u8 value; - switch (sd->chip_revision) { - case Rev072A: - value = sd->brightness; - reg_w_val(gspca_dev->dev, value, 0x8611); - reg_w_val(gspca_dev->dev, value, 0x8612); - reg_w_val(gspca_dev->dev, value, 0x8613); - reg_w_val(gspca_dev->dev, value, 0x8614); - break; - default: -/* case Rev012A: */ - setcontrast(gspca_dev); - break; - } + value = sd->brightness; + reg_w_val(gspca_dev->dev, 0x8611, value); + reg_w_val(gspca_dev->dev, 0x8612, value); + reg_w_val(gspca_dev->dev, 0x8613, value); + reg_w_val(gspca_dev->dev, 0x8614, value); } static void getbrightness(struct gspca_dev *gspca_dev) @@ -875,52 +885,38 @@ static void getbrightness(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; __u16 tot; - switch (sd->chip_revision) { - case Rev072A: - tot = 0; - reg_r(gspca_dev, 0x8611, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8612, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8613, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8614, 1); - tot += gspca_dev->usb_buf[0]; - sd->brightness = tot >> 2; - break; - default: -/* case Rev012A: */ - /* no way to read sensor settings */ - break; - } + tot = 0; + reg_r(gspca_dev, 0x8611, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8612, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8613, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8614, 1); + tot += gspca_dev->usb_buf[0]; + sd->brightness = tot >> 2; } +/* rev72a only */ static void getcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u16 tot; - switch (sd->chip_revision) { - case Rev072A: - tot = 0; - reg_r(gspca_dev, 0x8651, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8652, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8653, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8654, 1); - tot += gspca_dev->usb_buf[0]; - sd->contrast = tot << 6; - break; - default: -/* case Rev012A: */ - /* no way to read sensor settings */ - break; - } + tot = 0; + reg_r(gspca_dev, 0x8651, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8652, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8653, 1); + tot += gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8654, 1); + tot += gspca_dev->usb_buf[0]; + sd->contrast = tot << 6; PDEBUG(D_CONF, "get contrast %d", sd->contrast); } +/* rev 72a only */ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -940,6 +936,7 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +/* rev 72a only */ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -964,10 +961,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; sd->autogain = val; - if (val) - sd->ag_cnt = AG_CNT_START; - else - sd->ag_cnt = -1; + if (gspca_dev->streaming) + setautogain(gspca_dev); return 0; } @@ -979,38 +974,210 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +/* rev12a only */ +static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->white = val; + if (gspca_dev->streaming) + setwhite(gspca_dev); + return 0; +} + +static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->white; + return 0; +} + +/* rev12a only */ +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->exposure = val; + if (gspca_dev->streaming) + setexposure(gspca_dev); + return 0; +} + +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->exposure; + return 0; +} + +/* rev12a only */ +static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->gain = val; + if (gspca_dev->streaming) + setgain(gspca_dev); + return 0; +} + +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->gain; + return 0; +} + +/* control tables */ +static struct ctrl sd_ctrls_12a[] = { + { + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "While Balance", + .minimum = WHITE_MIN, + .maximum = WHITE_MAX, + .step = 1, + .default_value = WHITE_DEF, + }, + .set = sd_setwhite, + .get = sd_getwhite, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = EXPOSURE_MIN, + .maximum = EXPOSURE_MAX, + .step = 1, + .default_value = EXPOSURE_DEF, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = AUTOGAIN_MIN, + .maximum = AUTOGAIN_MAX, + .step = 1, + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = GAIN_MIN, + .maximum = GAIN_MAX, + .step = 1, + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, +}; + +static struct ctrl sd_ctrls_72a[] = { + { + { + .id = V4L2_CID_BRIGHTNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Brightness", + .minimum = BRIGHTNESS_MIN, + .maximum = BRIGHTNESS_MAX, + .step = 1, + .default_value = BRIGHTNESS_DEF, + }, + .set = sd_setbrightness, + .get = sd_getbrightness, + }, + { + { + .id = V4L2_CID_CONTRAST, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Contrast", + .minimum = CONTRAST_MIN, + .maximum = CONTRAST_MAX, + .step = 1, + .default_value = CONTRAST_DEF, + }, + .set = sd_setcontrast, + .get = sd_getcontrast, + }, + { + { + .id = V4L2_CID_AUTOGAIN, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Gain", + .minimum = AUTOGAIN_MIN, + .maximum = AUTOGAIN_MAX, + .step = 1, + .default_value = AUTOGAIN_DEF, + }, + .set = sd_setautogain, + .get = sd_getautogain, + }, +}; + /* sub-driver description */ -static const struct sd_desc sd_desc = { +static const struct sd_desc sd_desc_12a = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), + .ctrls = sd_ctrls_12a, + .nctrls = ARRAY_SIZE(sd_ctrls_12a), .config = sd_config, - .open = sd_open, - .start = sd_start, + .open = sd_open_12a, + .start = sd_start_12a, .stopN = sd_stopN, .stop0 = sd_stop0, .close = sd_close, .pkt_scan = sd_pkt_scan, +/* .dq_callback = do_autogain, * fixme */ +}; +static const struct sd_desc sd_desc_72a = { + .name = MODULE_NAME, + .ctrls = sd_ctrls_72a, + .nctrls = ARRAY_SIZE(sd_ctrls_72a), + .config = sd_config, + .open = sd_open_72a, + .start = sd_start_72a, + .stopN = sd_stopN, + .stop0 = sd_stop0, + .close = sd_close, + .pkt_scan = sd_pkt_scan, + .dq_callback = do_autogain, +}; +static const struct sd_desc *sd_desc[2] = { + &sd_desc_12a, + &sd_desc_72a }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x401a), DVNM("Creative Webcam Vista (PD1100)")}, - {USB_DEVICE(0x041e, 0x403b), DVNM("Creative Webcam Vista (VF0010)")}, - {USB_DEVICE(0x0458, 0x7004), DVNM("Genius VideoCAM Express V2")}, - {USB_DEVICE(0x046d, 0x0928), DVNM("Logitech QC Express Etch2")}, - {USB_DEVICE(0x046d, 0x0929), DVNM("Labtec Webcam Elch2")}, - {USB_DEVICE(0x046d, 0x092a), DVNM("Logitech QC for Notebook")}, - {USB_DEVICE(0x046d, 0x092b), DVNM("Labtec Webcam Plus")}, - {USB_DEVICE(0x046d, 0x092c), DVNM("Logitech QC chat Elch2")}, - {USB_DEVICE(0x046d, 0x092d), DVNM("Logitech QC Elch2")}, - {USB_DEVICE(0x046d, 0x092e), DVNM("Logitech QC Elch2")}, - {USB_DEVICE(0x046d, 0x092f), DVNM("Logitech QC Elch2")}, - {USB_DEVICE(0x04fc, 0x0561), DVNM("Flexcam 100")}, - {USB_DEVICE(0x060b, 0xa001), DVNM("Maxell Compact Pc PM3")}, - {USB_DEVICE(0x10fd, 0x7e50), DVNM("FlyCam Usb 100")}, - {USB_DEVICE(0xabcd, 0xcdee), DVNM("Petcam")}, + {USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A}, + {USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A}, + {USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A}, + {USB_DEVICE(0x046d, 0x0928), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x0929), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092a), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092b), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092c), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092d), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092e), .driver_info = Rev012A}, + {USB_DEVICE(0x046d, 0x092f), .driver_info = Rev012A}, + {USB_DEVICE(0x04fc, 0x0561), .driver_info = Rev072A}, + {USB_DEVICE(0x060b, 0xa001), .driver_info = Rev072A}, + {USB_DEVICE(0x10fd, 0x7e50), .driver_info = Rev072A}, + {USB_DEVICE(0xabcd, 0xcdee), .driver_info = Rev072A}, {} }; @@ -1020,7 +1187,9 @@ MODULE_DEVICE_TABLE(usb, device_table); static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + return gspca_dev_probe(intf, id, + sd_desc[id->driver_info], + sizeof(struct sd), THIS_MODULE); } @@ -1029,6 +1198,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/stk014.c b/linux/drivers/media/video/gspca/stk014.c index 90efde17b..387a8cf2b 100644 --- a/linux/drivers/media/video/gspca/stk014.c +++ b/linux/drivers/media/video/gspca/stk014.c @@ -296,7 +296,6 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; struct cam *cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x02; gspca_dev->cam.cam_mode = vga_mode; gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode); @@ -546,9 +545,8 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x05e1, 0x0893), DVNM("Syntek DV4000")}, + {USB_DEVICE(0x05e1, 0x0893)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -566,6 +564,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/sunplus.c b/linux/drivers/media/video/gspca/sunplus.c index 2ebf859fb..e1a7e53ba 100644 --- a/linux/drivers/media/video/gspca/sunplus.c +++ b/linux/drivers/media/video/gspca/sunplus.c @@ -832,229 +832,29 @@ static int sd_config(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; struct cam *cam; - __u16 vendor; - __u16 product; - __u8 fw; - - vendor = id->idVendor; - product = id->idProduct; - switch (vendor) { - case 0x041e: /* Creative cameras */ -/* switch (product) { */ -/* case 0x400b: */ -/* case 0x4012: */ -/* case 0x4013: */ -/* sd->bridge = BRIDGE_SPCA504C; */ -/* break; */ -/* } */ - break; - case 0x0458: /* Genius KYE cameras */ -/* switch (product) { */ -/* case 0x7006: */ - sd->bridge = BRIDGE_SPCA504B; -/* break; */ -/* } */ - break; - case 0x0461: /* MicroInnovation */ -/* switch (product) { */ -/* case 0x0821: */ - sd->bridge = BRIDGE_SPCA533; -/* break; */ -/* } */ - break; - case 0x046d: /* Logitech Labtec */ - switch (product) { - case 0x0905: - sd->subtype = LogitechClickSmart820; - sd->bridge = BRIDGE_SPCA533; - break; - case 0x0960: - sd->subtype = LogitechClickSmart420; - sd->bridge = BRIDGE_SPCA504C; - break; - } - break; - case 0x0471: /* Philips */ -/* switch (product) { */ -/* case 0x0322: */ - sd->bridge = BRIDGE_SPCA504B; -/* break; */ -/* } */ - break; - case 0x04a5: /* Benq */ - switch (product) { - case 0x3003: - sd->bridge = BRIDGE_SPCA504B; - break; - case 0x3008: - case 0x300a: - sd->bridge = BRIDGE_SPCA533; - break; - } - break; - case 0x04f1: /* JVC */ -/* switch (product) { */ -/* case 0x1001: */ - sd->bridge = BRIDGE_SPCA504B; -/* break; */ -/* } */ - break; - case 0x04fc: /* SunPlus */ - switch (product) { - case 0x500c: - sd->bridge = BRIDGE_SPCA504B; - break; - case 0x504a: + + cam = &gspca_dev->cam; + cam->epaddr = 0x01; + + sd->bridge = id->driver_info >> 8; + sd->subtype = id->driver_info; + + if (sd->subtype == AiptekMiniPenCam13) { /* try to get the firmware as some cam answer 2.0.1.2.2 * and should be a spca504b then overwrite that setting */ - reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1); - fw = gspca_dev->usb_buf[0]; - if (fw == 1) { - sd->subtype = AiptekMiniPenCam13; - sd->bridge = BRIDGE_SPCA504; - } else if (fw == 2) { - sd->bridge = BRIDGE_SPCA504B; - } else - return -ENODEV; - break; - case 0x504b: - sd->bridge = BRIDGE_SPCA504B; - break; - case 0x5330: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x5360: - sd->bridge = BRIDGE_SPCA536; - break; - case 0xffff: - sd->bridge = BRIDGE_SPCA504B; - break; - } - break; - case 0x052b: /* ?? Megapix */ -/* switch (product) { */ -/* case 0x1513: */ - sd->subtype = MegapixV4; - sd->bridge = BRIDGE_SPCA533; -/* break; */ -/* } */ - break; - case 0x0546: /* Polaroid */ - switch (product) { - case 0x3155: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x3191: - case 0x3273: + reg_r(dev, 0x20, 0, gspca_dev->usb_buf, 1); + switch (gspca_dev->usb_buf[0]) { + case 1: + break; /* (right bridge/subtype) */ + case 2: sd->bridge = BRIDGE_SPCA504B; + sd->subtype = 0; break; + default: + return -ENODEV; } - break; - case 0x055f: /* Mustek cameras */ - switch (product) { - case 0xc211: - sd->bridge = BRIDGE_SPCA536; - break; - case 0xc230: - case 0xc232: - sd->bridge = BRIDGE_SPCA533; - break; - case 0xc360: - sd->bridge = BRIDGE_SPCA536; - break; - case 0xc420: - sd->bridge = BRIDGE_SPCA504; - break; - case 0xc430: - case 0xc440: - sd->bridge = BRIDGE_SPCA533; - break; - case 0xc520: - sd->bridge = BRIDGE_SPCA504; - break; - case 0xc530: - case 0xc540: - case 0xc630: - case 0xc650: - sd->bridge = BRIDGE_SPCA533; - break; - } - break; - case 0x05da: /* Digital Dream cameras */ -/* switch (product) { */ -/* case 0x1018: */ - sd->bridge = BRIDGE_SPCA504B; -/* break; */ -/* } */ - break; - case 0x06d6: /* Trust */ -/* switch (product) { */ -/* case 0x0031: */ - sd->bridge = BRIDGE_SPCA533; /* SPCA533A */ -/* break; */ -/* } */ - break; - case 0x0733: /* Rebadged ViewQuest (Intel) and ViewQuest cameras */ - switch (product) { - case 0x1311: - case 0x1314: - case 0x2211: - case 0x2221: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x3261: - case 0x3281: - sd->bridge = BRIDGE_SPCA536; - break; - } - break; - case 0x08ca: /* Aiptek */ - switch (product) { - case 0x0104: - case 0x0106: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x2008: - sd->bridge = BRIDGE_SPCA504B; - break; - case 0x2010: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x2016: - case 0x2018: - sd->bridge = BRIDGE_SPCA504B; - break; - case 0x2020: - case 0x2022: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x2024: - sd->bridge = BRIDGE_SPCA536; - break; - case 0x2028: - sd->bridge = BRIDGE_SPCA533; - break; - case 0x2040: - case 0x2042: - case 0x2050: - case 0x2060: - sd->bridge = BRIDGE_SPCA536; - break; - } - break; - case 0x0d64: /* SunPlus */ -/* switch (product) { */ -/* case 0x0303: */ - sd->bridge = BRIDGE_SPCA536; -/* break; */ -/* } */ - break; } - cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; - cam->epaddr = 0x01; - switch (sd->bridge) { default: /* case BRIDGE_SPCA504B: */ @@ -1609,65 +1409,67 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name +#define BS(bridge, subtype) \ + .driver_info = (BRIDGE_ ## bridge << 8) \ + | (subtype) static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x400b), DVNM("Creative PC-CAM 600")}, - {USB_DEVICE(0x041e, 0x4012), DVNM("PC-Cam350")}, - {USB_DEVICE(0x041e, 0x4013), DVNM("Creative Pccam750")}, - {USB_DEVICE(0x0458, 0x7006), DVNM("Genius Dsc 1.3 Smart")}, - {USB_DEVICE(0x0461, 0x0821), DVNM("Fujifilm MV-1")}, - {USB_DEVICE(0x046d, 0x0905), DVNM("Logitech ClickSmart 820")}, - {USB_DEVICE(0x046d, 0x0960), DVNM("Logitech ClickSmart 420")}, - {USB_DEVICE(0x0471, 0x0322), DVNM("Philips DMVC1300K")}, - {USB_DEVICE(0x04a5, 0x3003), DVNM("Benq DC 1300")}, - {USB_DEVICE(0x04a5, 0x3008), DVNM("Benq DC 1500")}, - {USB_DEVICE(0x04a5, 0x300a), DVNM("Benq DC3410")}, - {USB_DEVICE(0x04f1, 0x1001), DVNM("JVC GC A50")}, - {USB_DEVICE(0x04fc, 0x500c), DVNM("Sunplus CA500C")}, - {USB_DEVICE(0x04fc, 0x504a), DVNM("Aiptek Mini PenCam 1.3")}, - {USB_DEVICE(0x04fc, 0x504b), DVNM("Maxell MaxPocket LE 1.3")}, - {USB_DEVICE(0x04fc, 0x5330), DVNM("Digitrex 2110")}, - {USB_DEVICE(0x04fc, 0x5360), DVNM("Sunplus Generic")}, - {USB_DEVICE(0x04fc, 0xffff), DVNM("Pure DigitalDakota")}, - {USB_DEVICE(0x052b, 0x1513), DVNM("Megapix V4")}, - {USB_DEVICE(0x0546, 0x3155), DVNM("Polaroid PDC3070")}, - {USB_DEVICE(0x0546, 0x3191), DVNM("Polaroid Ion 80")}, - {USB_DEVICE(0x0546, 0x3273), DVNM("Polaroid PDC2030")}, - {USB_DEVICE(0x055f, 0xc211), DVNM("Kowa Bs888e Microcamera")}, - {USB_DEVICE(0x055f, 0xc230), DVNM("Mustek Digicam 330K")}, - {USB_DEVICE(0x055f, 0xc232), DVNM("Mustek MDC3500")}, - {USB_DEVICE(0x055f, 0xc360), DVNM("Mustek DV4000 Mpeg4 ")}, - {USB_DEVICE(0x055f, 0xc420), DVNM("Mustek gSmart Mini 2")}, - {USB_DEVICE(0x055f, 0xc430), DVNM("Mustek Gsmart LCD 2")}, - {USB_DEVICE(0x055f, 0xc440), DVNM("Mustek DV 3000")}, - {USB_DEVICE(0x055f, 0xc520), DVNM("Mustek gSmart Mini 3")}, - {USB_DEVICE(0x055f, 0xc530), DVNM("Mustek Gsmart LCD 3")}, - {USB_DEVICE(0x055f, 0xc540), DVNM("Gsmart D30")}, - {USB_DEVICE(0x055f, 0xc630), DVNM("Mustek MDC4000")}, - {USB_DEVICE(0x055f, 0xc650), DVNM("Mustek MDC5500Z")}, - {USB_DEVICE(0x05da, 0x1018), DVNM("Digital Dream Enigma 1.3")}, - {USB_DEVICE(0x06d6, 0x0031), DVNM("Trust 610 LCD PowerC@m Zoom")}, - {USB_DEVICE(0x0733, 0x1311), DVNM("Digital Dream Epsilon 1.3")}, - {USB_DEVICE(0x0733, 0x1314), DVNM("Mercury 2.1MEG Deluxe Classic Cam")}, - {USB_DEVICE(0x0733, 0x2211), DVNM("Jenoptik jdc 21 LCD")}, - {USB_DEVICE(0x0733, 0x2221), DVNM("Mercury Digital Pro 3.1p")}, - {USB_DEVICE(0x0733, 0x3261), DVNM("Concord 3045 spca536a")}, - {USB_DEVICE(0x0733, 0x3281), DVNM("Cyberpix S550V")}, - {USB_DEVICE(0x08ca, 0x0104), DVNM("Aiptek PocketDVII 1.3")}, - {USB_DEVICE(0x08ca, 0x0106), DVNM("Aiptek Pocket DV3100+")}, - {USB_DEVICE(0x08ca, 0x2008), DVNM("Aiptek Mini PenCam 2 M")}, - {USB_DEVICE(0x08ca, 0x2010), DVNM("Aiptek PocketCam 3M")}, - {USB_DEVICE(0x08ca, 0x2016), DVNM("Aiptek PocketCam 2 Mega")}, - {USB_DEVICE(0x08ca, 0x2018), DVNM("Aiptek Pencam SD 2M")}, - {USB_DEVICE(0x08ca, 0x2020), DVNM("Aiptek Slim 3000F")}, - {USB_DEVICE(0x08ca, 0x2022), DVNM("Aiptek Slim 3200")}, - {USB_DEVICE(0x08ca, 0x2024), DVNM("Aiptek DV3500 Mpeg4 ")}, - {USB_DEVICE(0x08ca, 0x2028), DVNM("Aiptek PocketCam4M")}, - {USB_DEVICE(0x08ca, 0x2040), DVNM("Aiptek PocketDV4100M")}, - {USB_DEVICE(0x08ca, 0x2042), DVNM("Aiptek PocketDV5100")}, - {USB_DEVICE(0x08ca, 0x2050), DVNM("Medion MD 41437")}, - {USB_DEVICE(0x08ca, 0x2060), DVNM("Aiptek PocketDV5300")}, - {USB_DEVICE(0x0d64, 0x0303), DVNM("Sunplus FashionCam DXG")}, + {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)}, + {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)}, + {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)}, + {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)}, + {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)}, + {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)}, + {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)}, + {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)}, + {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)}, + {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)}, + {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)}, + {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)}, + {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)}, + {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)}, + {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)}, + {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)}, + {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)}, + {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)}, + {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)}, + {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)}, + {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)}, + {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)}, + {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)}, + {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)}, + {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)}, + {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)}, + {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)}, + {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)}, + {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)}, + {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)}, + {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)}, + {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)}, + {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)}, + {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -1685,6 +1487,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/t613.c b/linux/drivers/media/video/gspca/t613.c index 5188ec486..27bff51a0 100644 --- a/linux/drivers/media/video/gspca/t613.c +++ b/linux/drivers/media/video/gspca/t613.c @@ -30,7 +30,7 @@ #define MAX_GAMMA 0x10 /* 0 to 15 */ -#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 3) +#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0) MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>"); MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver"); @@ -233,7 +233,7 @@ static char *effects_control[] = { static struct v4l2_pix_format vga_mode_t16[] = { {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 160, - .sizeimage = 160 * 120 * 3 / 8 + 590, + .sizeimage = 160 * 120 * 4 / 8 + 590, .colorspace = V4L2_COLORSPACE_JPEG, .priv = 4}, {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, @@ -420,22 +420,8 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; -#if 0 - __u16 vendor; - __u16 product; - - vendor = id->idVendor; - product = id->idProduct; - switch (vendor) { - case 0x17a1: - /* t613 + tas5130A */ - /* Currently one sensor supported... */ - break; - } -#endif cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; cam->cam_mode = vga_mode_t16; @@ -1032,9 +1018,8 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x17a1, 0x0128), DVNM("XPX Webcam")}, + {USB_DEVICE(0x17a1, 0x0128)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -1052,6 +1037,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/tv8532.c b/linux/drivers/media/video/gspca/tv8532.c index 7de866036..c55dbe8ac 100644 --- a/linux/drivers/media/video/gspca/tv8532.c +++ b/linux/drivers/media/video/gspca/tv8532.c @@ -246,7 +246,6 @@ static int sd_config(struct gspca_dev *gspca_dev, tv_8532WriteEEprom(gspca_dev); cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 1; cam->cam_mode = sif_mode; cam->nmodes = sizeof sif_mode / sizeof sif_mode[0]; @@ -630,13 +629,12 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x046d, 0x0920), DVNM("QC Express")}, - {USB_DEVICE(0x046d, 0x0921), DVNM("Labtec Webcam")}, - {USB_DEVICE(0x0545, 0x808b), DVNM("Veo Stingray")}, - {USB_DEVICE(0x0545, 0x8333), DVNM("Veo Stingray")}, - {USB_DEVICE(0x0923, 0x010f), DVNM("ICM532 cams")}, + {USB_DEVICE(0x046d, 0x0920)}, + {USB_DEVICE(0x046d, 0x0921)}, + {USB_DEVICE(0x0545, 0x808b)}, + {USB_DEVICE(0x0545, 0x8333)}, + {USB_DEVICE(0x0923, 0x010f)}, {} }; @@ -655,6 +653,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c index c811379c7..f37c63d6d 100644 --- a/linux/drivers/media/video/gspca/vc032x.c +++ b/linux/drivers/media/video/gspca/vc032x.c @@ -88,12 +88,12 @@ static struct ctrl sd_ctrls[] = { static struct v4l2_pix_format vc0321_mode[] = { {320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, - .bytesperline = 320 * 2, + .bytesperline = 320, .sizeimage = 320 * 240 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, {640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, - .bytesperline = 640 * 2, + .bytesperline = 640, .sizeimage = 640 * 480 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, @@ -1596,30 +1596,10 @@ static int sd_config(struct gspca_dev *gspca_dev, struct usb_device *dev = gspca_dev->dev; struct cam *cam; int sensor; - __u16 product; - - product = id->idProduct; - sd->bridge = BRIDGE_VC0321; - switch (id->idVendor) { - case 0x0ac8: /* Vimicro z-star */ - switch (product) { - case 0x0323: - sd->bridge = BRIDGE_VC0323; - break; - } - break; - case 0x17ef: /* Lenovo */ -/* switch (product) { */ -/* case 0x4802: * Lenovo MI1310_SOC */ - sd->bridge = BRIDGE_VC0323; -/* break; */ -/* } */ - break; - } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x02; + sd->bridge = id->driver_info; if (sd->bridge == BRIDGE_VC0321) { cam->cam_mode = vc0321_mode; cam->nmodes = ARRAY_SIZE(vc0321_mode); @@ -1965,16 +1945,15 @@ static const struct sd_desc sd_desc = { }; /* -- module initialisation -- */ -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x046d, 0x0892), DVNM("Logitech Orbicam")}, - {USB_DEVICE(0x046d, 0x0896), DVNM("Logitech Orbicam")}, - {USB_DEVICE(0x0ac8, 0x0321), DVNM("Vimicro generic vc0321")}, - {USB_DEVICE(0x0ac8, 0x0323), DVNM("Vimicro Vc0323")}, - {USB_DEVICE(0x0ac8, 0x0328), DVNM("A4Tech PK-130MG")}, - {USB_DEVICE(0x0ac8, 0xc001), DVNM("Sony embedded vimicro")}, - {USB_DEVICE(0x0ac8, 0xc002), DVNM("Sony embedded vimicro")}, - {USB_DEVICE(0x17ef, 0x4802), DVNM("Lenovo Vc0323+MI1310_SOC")}, + {USB_DEVICE(0x046d, 0x0892), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x046d, 0x0896), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0x0321), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0x0323), .driver_info = BRIDGE_VC0323}, + {USB_DEVICE(0x0ac8, 0x0328), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0xc001), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x0ac8, 0xc002), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x17ef, 0x4802), .driver_info = BRIDGE_VC0323}, {} }; MODULE_DEVICE_TABLE(usb, device_table); @@ -1992,6 +1971,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; /* -- module insert / remove -- */ diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c index f7f8c61b3..a3f109ac4 100644 --- a/linux/drivers/media/video/gspca/zc3xx.c +++ b/linux/drivers/media/video/gspca/zc3xx.c @@ -70,6 +70,10 @@ struct sd { unsigned short chip_revision; }; +#define DRIVER_INFO(sensor, flags) .driver_info = ((sensor) << 8) | (flags) +#define DRIVER_INFO_GET_SENSOR(driver_info) ((driver_info) >> 8) +#define DRIVER_INFO_GET_FLAGS(driver_info) ((driver_info) & 0xff) + /* V4L2 controls supported by the driver */ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); @@ -6474,7 +6478,7 @@ static void setcontrast(struct gspca_dev *gspca_dev) NULL, Tgradient_1, Tgradient_2, Tgradient_3, Tgradient_4, Tgradient_5, Tgradient_6 }; -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG __u8 v[16]; #endif @@ -6492,7 +6496,7 @@ static void setcontrast(struct gspca_dev *gspca_dev) else if (g <= 0) g = 1; reg_w(dev, g, 0x0120 + i); /* gamma */ -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG if (gspca_debug & D_CONF) v[i] = g; #endif @@ -6512,7 +6516,7 @@ static void setcontrast(struct gspca_dev *gspca_dev) g = 1; } reg_w(dev, g, 0x0130 + i); /* gradient */ -#ifdef CONFIG_VIDEO_ADV_DEBUG +#ifdef GSPCA_DEBUG if (gspca_debug & D_CONF) v[i] = g; #endif @@ -6969,8 +6973,13 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev) case SENSOR_MC501CB: return -1; /* don't probe */ case SENSOR_TAS5130C_VF0250: - /* may probe but with write in reg 0x0010 */ + /* may probe but with no write in reg 0x0010 */ return -1; /* don't probe */ + case SENSOR_PAS106: + sensor = sif_probe(gspca_dev); + if (sensor >= 0) + return sensor; + break; } sensor = vga_2wr_probe(gspca_dev); if (sensor >= 0) { @@ -6979,12 +6988,10 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev) /* next probe is needed for OmniVision ? */ } sensor2 = vga_3wr_probe(gspca_dev); - if (sensor2 >= 0) { - if (sensor >= 0) - return sensor; - return sensor2; - } - return sif_probe(gspca_dev); + if (sensor2 >= 0 + && sensor >= 0) + return sensor; + return sensor2; } /* this function is called at probe time */ @@ -7017,31 +7024,8 @@ static int sd_config(struct gspca_dev *gspca_dev, /* define some sensors from the vendor/product */ sd->sharpness = 2; - sd->sensor = -1; - switch (id->idVendor) { - case 0x041e: /* Creative */ - switch (id->idProduct) { - case 0x4051: /* zc301 chips */ - case 0x4053: - sd->sensor = SENSOR_TAS5130C_VF0250; - break; - } - break; - case 0x046d: /* Logitech Labtec */ - switch (id->idProduct) { - case 0x08dd: - sd->sensor = SENSOR_MC501CB; - break; - } - break; - case 0x0ac8: /* Vimicro z-star */ - switch (id->idProduct) { - case 0x305b: - sd->sensor = SENSOR_TAS5130C_VF0250; - break; - } - break; - } + sd->sensor = DRIVER_INFO_GET_SENSOR(id->driver_info); + gspca_dev->flags = DRIVER_INFO_GET_FLAGS(id->driver_info); sensor = zcxx_probeSensor(gspca_dev); if (sensor >= 0) PDEBUG(D_PROBE, "probe sensor -> %02x", sensor); @@ -7158,7 +7142,6 @@ static int sd_config(struct gspca_dev *gspca_dev, } cam = &gspca_dev->cam; - cam->dev_name = (char *) id->driver_info; cam->epaddr = 0x01; /*fixme:test*/ gspca_dev->nbalt--; @@ -7535,70 +7518,71 @@ static const struct sd_desc sd_desc = { .querymenu = sd_querymenu, }; -#define DVNM(name) .driver_info = (kernel_ulong_t) name static const __devinitdata struct usb_device_id device_table[] = { - {USB_DEVICE(0x041e, 0x041e), DVNM("Creative WebCam Live!")}, + {USB_DEVICE(0x041e, 0x041e)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x041e, 0x4017), DVNM("Creative Webcam Mobile PD1090")}, - {USB_DEVICE(0x041e, 0x401c), DVNM("Creative NX")}, - {USB_DEVICE(0x041e, 0x401e), DVNM("Creative Nx Pro")}, - {USB_DEVICE(0x041e, 0x401f), DVNM("Creative Webcam Notebook PD1171")}, + {USB_DEVICE(0x041e, 0x4017)}, + {USB_DEVICE(0x041e, 0x401c), DRIVER_INFO(SENSOR_PAS106, 0)}, + {USB_DEVICE(0x041e, 0x401e)}, + {USB_DEVICE(0x041e, 0x401f)}, #endif - {USB_DEVICE(0x041e, 0x4029), DVNM("Creative WebCam Vista Pro")}, + {USB_DEVICE(0x041e, 0x4029)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x041e, 0x4034), DVNM("Creative Instant P0620")}, - {USB_DEVICE(0x041e, 0x4035), DVNM("Creative Instant P0620D")}, - {USB_DEVICE(0x041e, 0x4036), DVNM("Creative Live !")}, - {USB_DEVICE(0x041e, 0x403a), DVNM("Creative Nx Pro 2")}, + {USB_DEVICE(0x041e, 0x4034), DRIVER_INFO(SENSOR_PAS106, 0)}, + {USB_DEVICE(0x041e, 0x4035), DRIVER_INFO(SENSOR_PAS106, 0)}, + {USB_DEVICE(0x041e, 0x4036)}, + {USB_DEVICE(0x041e, 0x403a)}, #endif - {USB_DEVICE(0x041e, 0x4051), DVNM("Creative Notebook Pro (VF0250)")}, - {USB_DEVICE(0x041e, 0x4053), DVNM("Creative Live!Cam Video IM")}, + {USB_DEVICE(0x041e, 0x4051), DRIVER_INFO(SENSOR_TAS5130C_VF0250, 0)}, + {USB_DEVICE(0x041e, 0x4053), DRIVER_INFO(SENSOR_TAS5130C_VF0250, 0)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x0458, 0x7007), DVNM("Genius VideoCam V2")}, - {USB_DEVICE(0x0458, 0x700c), DVNM("Genius VideoCam V3")}, - {USB_DEVICE(0x0458, 0x700f), DVNM("Genius VideoCam Web V2")}, + {USB_DEVICE(0x0458, 0x7007)}, + {USB_DEVICE(0x0458, 0x700c)}, + {USB_DEVICE(0x0458, 0x700f)}, #endif - {USB_DEVICE(0x0461, 0x0a00), DVNM("MicroInnovation WebCam320")}, - {USB_DEVICE(0x046d, 0x08a0), DVNM("Logitech QC IM")}, - {USB_DEVICE(0x046d, 0x08a1), DVNM("Logitech QC IM 0x08A1 +sound")}, - {USB_DEVICE(0x046d, 0x08a2), DVNM("Labtec Webcam Pro")}, - {USB_DEVICE(0x046d, 0x08a3), DVNM("Logitech QC Chat")}, - {USB_DEVICE(0x046d, 0x08a6), DVNM("Logitech QCim")}, - {USB_DEVICE(0x046d, 0x08a7), DVNM("Logitech QuickCam Image")}, - {USB_DEVICE(0x046d, 0x08a9), DVNM("Logitech Notebook Deluxe")}, - {USB_DEVICE(0x046d, 0x08aa), DVNM("Labtec Webcam Notebook")}, - {USB_DEVICE(0x046d, 0x08ac), DVNM("Logitech QuickCam Cool")}, - {USB_DEVICE(0x046d, 0x08ad), DVNM("Logitech QCCommunicate STX")}, + {USB_DEVICE(0x0461, 0x0a00)}, + {USB_DEVICE(0x046d, 0x08a0)}, + {USB_DEVICE(0x046d, 0x08a1)}, + {USB_DEVICE(0x046d, 0x08a2)}, + {USB_DEVICE(0x046d, 0x08a3)}, + {USB_DEVICE(0x046d, 0x08a6)}, + {USB_DEVICE(0x046d, 0x08a7)}, + {USB_DEVICE(0x046d, 0x08a9)}, + {USB_DEVICE(0x046d, 0x08aa)}, + {USB_DEVICE(0x046d, 0x08ac)}, + {USB_DEVICE(0x046d, 0x08ad)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x046d, 0x08ae), DVNM("Logitech QuickCam for Notebooks")}, + {USB_DEVICE(0x046d, 0x08ae)}, #endif - {USB_DEVICE(0x046d, 0x08af), DVNM("Logitech QuickCam Cool")}, - {USB_DEVICE(0x046d, 0x08b9), DVNM("Logitech QC IM ???")}, - {USB_DEVICE(0x046d, 0x08d7), DVNM("Logitech QCam STX")}, - {USB_DEVICE(0x046d, 0x08d9), DVNM("Logitech QuickCam IM/Connect")}, - {USB_DEVICE(0x046d, 0x08d8), DVNM("Logitech Notebook Deluxe")}, - {USB_DEVICE(0x046d, 0x08da), DVNM("Logitech QuickCam Messenger")}, - {USB_DEVICE(0x046d, 0x08dd), DVNM("Logitech QuickCam for Notebooks")}, - {USB_DEVICE(0x0471, 0x0325), DVNM("Philips SPC 200 NC")}, - {USB_DEVICE(0x0471, 0x0326), DVNM("Philips SPC 300 NC")}, - {USB_DEVICE(0x0471, 0x032d), DVNM("Philips spc210nc")}, - {USB_DEVICE(0x0471, 0x032e), DVNM("Philips spc315nc")}, - {USB_DEVICE(0x055f, 0xc005), DVNM("Mustek Wcam300A")}, + {USB_DEVICE(0x046d, 0x08af)}, + {USB_DEVICE(0x046d, 0x08b9)}, + {USB_DEVICE(0x046d, 0x08d7)}, + {USB_DEVICE(0x046d, 0x08d9)}, + {USB_DEVICE(0x046d, 0x08d8)}, + {USB_DEVICE(0x046d, 0x08da)}, + {USB_DEVICE(0x046d, 0x08dd), DRIVER_INFO(SENSOR_MC501CB, 0)}, + {USB_DEVICE(0x0471, 0x0325), DRIVER_INFO(SENSOR_PAS106, + GSPCA_SENSOR_UPSIDE_DOWN_FLAG)}, + {USB_DEVICE(0x0471, 0x0326), DRIVER_INFO(SENSOR_PAS106, + GSPCA_SENSOR_UPSIDE_DOWN_FLAG)}, + {USB_DEVICE(0x0471, 0x032d), DRIVER_INFO(SENSOR_PAS106, 0)}, + {USB_DEVICE(0x0471, 0x032e), DRIVER_INFO(SENSOR_PAS106, 0)}, + {USB_DEVICE(0x055f, 0xc005)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x055f, 0xd003), DVNM("Mustek WCam300A")}, - {USB_DEVICE(0x055f, 0xd004), DVNM("Mustek WCam300 AN")}, + {USB_DEVICE(0x055f, 0xd003)}, + {USB_DEVICE(0x055f, 0xd004)}, #endif - {USB_DEVICE(0x0698, 0x2003), DVNM("CTX M730V built in")}, - {USB_DEVICE(0x0ac8, 0x0302), DVNM("Z-star Vimicro zc0302")}, + {USB_DEVICE(0x0698, 0x2003)}, + {USB_DEVICE(0x0ac8, 0x0302)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x0ac8, 0x301b), DVNM("Z-Star zc301b")}, - {USB_DEVICE(0x0ac8, 0x303b), DVNM("Vimicro 0x303b")}, + {USB_DEVICE(0x0ac8, 0x301b)}, + {USB_DEVICE(0x0ac8, 0x303b)}, #endif - {USB_DEVICE(0x0ac8, 0x305b), DVNM("Z-star Vimicro zc0305b")}, + {USB_DEVICE(0x0ac8, 0x305b), DRIVER_INFO(SENSOR_TAS5130C_VF0250, 0)}, #ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x0ac8, 0x307b), DVNM("Z-Star 307b")}, - {USB_DEVICE(0x10fd, 0x0128), DVNM("Typhoon Webshot II 300k 0x0128")}, - {USB_DEVICE(0x10fd, 0x8050), DVNM("Typhoon Webshot II USB 300k")}, + {USB_DEVICE(0x0ac8, 0x307b)}, + {USB_DEVICE(0x10fd, 0x0128)}, + {USB_DEVICE(0x10fd, 0x8050)}, #endif {} /* end of entry */ }; @@ -7619,6 +7603,10 @@ static struct usb_driver sd_driver = { .id_table = device_table, .probe = sd_probe, .disconnect = gspca_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif }; static int __init sd_mod_init(void) diff --git a/linux/drivers/media/video/ivtv/Kconfig b/linux/drivers/media/video/ivtv/Kconfig index 5d7ee8fcd..0069898bd 100644 --- a/linux/drivers/media/video/ivtv/Kconfig +++ b/linux/drivers/media/video/ivtv/Kconfig @@ -2,9 +2,7 @@ config VIDEO_IVTV tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support" depends on VIDEO_V4L1 && VIDEO_V4L2 && PCI && I2C && EXPERIMENTAL depends on INPUT # due to VIDEO_IR - depends on HOTPLUG # due to FW_LOADER select I2C_ALGOBIT - select FW_LOADER select VIDEO_IR select VIDEO_TUNER select VIDEO_TVEEPROM diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c index c0b98a83b..89a16bfeb 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.c +++ b/linux/drivers/media/video/ivtv/ivtv-driver.c @@ -465,9 +465,8 @@ static void ivtv_process_eeprom(struct ivtv *itv) if (itv->options.radio == -1) itv->options.radio = (tv.has_radio != 0); /* only enable newi2c if an IR blaster is present */ - /* FIXME: for 2.6.20 the test against 2 should be removed */ - if (itv->options.newi2c == -1 && tv.has_ir != -1 && tv.has_ir != 2) { - itv->options.newi2c = (tv.has_ir & 2) ? 1 : 0; + if (itv->options.newi2c == -1 && tv.has_ir) { + itv->options.newi2c = (tv.has_ir & 4) ? 1 : 0; if (itv->options.newi2c) { IVTV_INFO("Reopen i2c bus for IR-blaster support\n"); exit_ivtv_i2c(itv); @@ -689,7 +688,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv) spin_lock_init(&itv->lock); spin_lock_init(&itv->dma_reg_lock); - itv->irq_work_queues = create_workqueue(itv->name); + itv->irq_work_queues = create_singlethread_workqueue(itv->name); if (itv->irq_work_queues == NULL) { IVTV_ERR("Could not create ivtv workqueue\n"); return -1; diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h index d66ee14b6..6e0ca223a 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.h +++ b/linux/drivers/media/video/ivtv/ivtv-driver.h @@ -252,6 +252,7 @@ struct ivtv_mailbox_data { #define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */ #define IVTV_F_I_INITED 21 /* set after first open */ #define IVTV_F_I_FAILED 22 /* set if first open failed */ +#define IVTV_F_I_WORK_INITED 23 /* worker thread was initialized */ /* Event notifications */ #define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */ diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c index 7ec5c99f9..304261efc 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.c +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.c @@ -39,7 +39,7 @@ associated VBI streams are also automatically claimed. Possible error returns: -EBUSY if someone else has claimed the stream or 0 on success. */ -int ivtv_claim_stream(struct ivtv_open_id *id, int type) +static int ivtv_claim_stream(struct ivtv_open_id *id, int type) { struct ivtv *itv = id->itv; struct ivtv_stream *s = &itv->streams[type]; diff --git a/linux/drivers/media/video/ivtv/ivtv-fileops.h b/linux/drivers/media/video/ivtv/ivtv-fileops.h index 2c8d5186c..df81e7901 100644 --- a/linux/drivers/media/video/ivtv/ivtv-fileops.h +++ b/linux/drivers/media/video/ivtv/ivtv-fileops.h @@ -38,11 +38,6 @@ void ivtv_unmute(struct ivtv *itv); /* Utilities */ -/* Try to claim a stream for the filehandle. Return 0 on success, - -EBUSY if stream already claimed. Once a stream is claimed, it - remains claimed until the associated filehandle is closed. */ -int ivtv_claim_stream(struct ivtv_open_id *id, int type); - /* Release a previously claimed stream. */ void ivtv_release_stream(struct ivtv_stream *s); diff --git a/linux/drivers/media/video/ivtv/ivtv-ioctl.c b/linux/drivers/media/video/ivtv/ivtv-ioctl.c index 52e00a7f3..61030309d 100644 --- a/linux/drivers/media/video/ivtv/ivtv-ioctl.c +++ b/linux/drivers/media/video/ivtv/ivtv-ioctl.c @@ -1842,69 +1842,73 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, return res; } -void ivtv_set_funcs(struct video_device *vdev) -{ - vdev->vidioc_querycap = ivtv_querycap; - vdev->vidioc_g_priority = ivtv_g_priority; - vdev->vidioc_s_priority = ivtv_s_priority; - vdev->vidioc_s_audio = ivtv_s_audio; - vdev->vidioc_g_audio = ivtv_g_audio; - vdev->vidioc_enumaudio = ivtv_enumaudio; - vdev->vidioc_s_audout = ivtv_s_audout; - vdev->vidioc_g_audout = ivtv_g_audout; - vdev->vidioc_enum_input = ivtv_enum_input; - vdev->vidioc_enum_output = ivtv_enum_output; - vdev->vidioc_enumaudout = ivtv_enumaudout; - vdev->vidioc_cropcap = ivtv_cropcap; - vdev->vidioc_s_crop = ivtv_s_crop; - vdev->vidioc_g_crop = ivtv_g_crop; - vdev->vidioc_g_input = ivtv_g_input; - vdev->vidioc_s_input = ivtv_s_input; - vdev->vidioc_g_output = ivtv_g_output; - vdev->vidioc_s_output = ivtv_s_output; - vdev->vidioc_g_frequency = ivtv_g_frequency; - vdev->vidioc_s_frequency = ivtv_s_frequency; - vdev->vidioc_s_tuner = ivtv_s_tuner; - vdev->vidioc_g_tuner = ivtv_g_tuner; - vdev->vidioc_g_enc_index = ivtv_g_enc_index; - vdev->vidioc_g_fbuf = ivtv_g_fbuf; - vdev->vidioc_s_fbuf = ivtv_s_fbuf; - vdev->vidioc_g_std = ivtv_g_std; - vdev->vidioc_s_std = ivtv_s_std; - vdev->vidioc_overlay = ivtv_overlay; - vdev->vidioc_log_status = ivtv_log_status; - vdev->vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap; - vdev->vidioc_encoder_cmd = ivtv_encoder_cmd; - vdev->vidioc_try_encoder_cmd = ivtv_try_encoder_cmd; - vdev->vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out; - vdev->vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap; - vdev->vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap; - vdev->vidioc_g_fmt_sliced_vbi_cap = ivtv_g_fmt_sliced_vbi_cap; - vdev->vidioc_g_fmt_vid_out = ivtv_g_fmt_vid_out; - vdev->vidioc_g_fmt_vid_out_overlay = ivtv_g_fmt_vid_out_overlay; - vdev->vidioc_g_fmt_sliced_vbi_out = ivtv_g_fmt_sliced_vbi_out; - vdev->vidioc_s_fmt_vid_cap = ivtv_s_fmt_vid_cap; - vdev->vidioc_s_fmt_vbi_cap = ivtv_s_fmt_vbi_cap; - vdev->vidioc_s_fmt_sliced_vbi_cap = ivtv_s_fmt_sliced_vbi_cap; - vdev->vidioc_s_fmt_vid_out = ivtv_s_fmt_vid_out; - vdev->vidioc_s_fmt_vid_out_overlay = ivtv_s_fmt_vid_out_overlay; - vdev->vidioc_s_fmt_sliced_vbi_out = ivtv_s_fmt_sliced_vbi_out; - vdev->vidioc_try_fmt_vid_cap = ivtv_try_fmt_vid_cap; - vdev->vidioc_try_fmt_vbi_cap = ivtv_try_fmt_vbi_cap; - vdev->vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap; - vdev->vidioc_try_fmt_vid_out = ivtv_try_fmt_vid_out; - vdev->vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay; - vdev->vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out; - vdev->vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap; - vdev->vidioc_g_chip_ident = ivtv_g_chip_ident; +static const struct v4l2_ioctl_ops ivtv_ioctl_ops = { + .vidioc_querycap = ivtv_querycap, + .vidioc_g_priority = ivtv_g_priority, + .vidioc_s_priority = ivtv_s_priority, + .vidioc_s_audio = ivtv_s_audio, + .vidioc_g_audio = ivtv_g_audio, + .vidioc_enumaudio = ivtv_enumaudio, + .vidioc_s_audout = ivtv_s_audout, + .vidioc_g_audout = ivtv_g_audout, + .vidioc_enum_input = ivtv_enum_input, + .vidioc_enum_output = ivtv_enum_output, + .vidioc_enumaudout = ivtv_enumaudout, + .vidioc_cropcap = ivtv_cropcap, + .vidioc_s_crop = ivtv_s_crop, + .vidioc_g_crop = ivtv_g_crop, + .vidioc_g_input = ivtv_g_input, + .vidioc_s_input = ivtv_s_input, + .vidioc_g_output = ivtv_g_output, + .vidioc_s_output = ivtv_s_output, + .vidioc_g_frequency = ivtv_g_frequency, + .vidioc_s_frequency = ivtv_s_frequency, + .vidioc_s_tuner = ivtv_s_tuner, + .vidioc_g_tuner = ivtv_g_tuner, + .vidioc_g_enc_index = ivtv_g_enc_index, + .vidioc_g_fbuf = ivtv_g_fbuf, + .vidioc_s_fbuf = ivtv_s_fbuf, + .vidioc_g_std = ivtv_g_std, + .vidioc_s_std = ivtv_s_std, + .vidioc_overlay = ivtv_overlay, + .vidioc_log_status = ivtv_log_status, + .vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap, + .vidioc_encoder_cmd = ivtv_encoder_cmd, + .vidioc_try_encoder_cmd = ivtv_try_encoder_cmd, + .vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out, + .vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap, + .vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap, + .vidioc_g_fmt_sliced_vbi_cap = ivtv_g_fmt_sliced_vbi_cap, + .vidioc_g_fmt_vid_out = ivtv_g_fmt_vid_out, + .vidioc_g_fmt_vid_out_overlay = ivtv_g_fmt_vid_out_overlay, + .vidioc_g_fmt_sliced_vbi_out = ivtv_g_fmt_sliced_vbi_out, + .vidioc_s_fmt_vid_cap = ivtv_s_fmt_vid_cap, + .vidioc_s_fmt_vbi_cap = ivtv_s_fmt_vbi_cap, + .vidioc_s_fmt_sliced_vbi_cap = ivtv_s_fmt_sliced_vbi_cap, + .vidioc_s_fmt_vid_out = ivtv_s_fmt_vid_out, + .vidioc_s_fmt_vid_out_overlay = ivtv_s_fmt_vid_out_overlay, + .vidioc_s_fmt_sliced_vbi_out = ivtv_s_fmt_sliced_vbi_out, + .vidioc_try_fmt_vid_cap = ivtv_try_fmt_vid_cap, + .vidioc_try_fmt_vbi_cap = ivtv_try_fmt_vbi_cap, + .vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap, + .vidioc_try_fmt_vid_out = ivtv_try_fmt_vid_out, + .vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay, + .vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out, + .vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap, + .vidioc_g_chip_ident = ivtv_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG - vdev->vidioc_g_register = ivtv_g_register; - vdev->vidioc_s_register = ivtv_s_register; + .vidioc_g_register = ivtv_g_register, + .vidioc_s_register = ivtv_s_register, #endif - vdev->vidioc_default = ivtv_default; - vdev->vidioc_queryctrl = ivtv_queryctrl; - vdev->vidioc_querymenu = ivtv_querymenu; - vdev->vidioc_g_ext_ctrls = ivtv_g_ext_ctrls; - vdev->vidioc_s_ext_ctrls = ivtv_s_ext_ctrls; - vdev->vidioc_try_ext_ctrls = ivtv_try_ext_ctrls; + .vidioc_default = ivtv_default, + .vidioc_queryctrl = ivtv_queryctrl, + .vidioc_querymenu = ivtv_querymenu, + .vidioc_g_ext_ctrls = ivtv_g_ext_ctrls, + .vidioc_s_ext_ctrls = ivtv_s_ext_ctrls, + .vidioc_try_ext_ctrls = ivtv_try_ext_ctrls, +}; + +void ivtv_set_funcs(struct video_device *vdev) +{ + vdev->ioctl_ops = &ivtv_ioctl_ops; } diff --git a/linux/drivers/media/video/ivtv/ivtv-irq.c b/linux/drivers/media/video/ivtv/ivtv-irq.c index d5ac766c1..59fe56171 100644 --- a/linux/drivers/media/video/ivtv/ivtv-irq.c +++ b/linux/drivers/media/video/ivtv/ivtv-irq.c @@ -82,6 +82,13 @@ void ivtv_irq_work_handler(void *arg) DEFINE_WAIT(wait); + if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) { + struct sched_param param = { .sched_priority = 99 }; + + /* This thread must use the FIFO scheduler as it + is realtime sensitive. */ + sched_setscheduler(current, SCHED_FIFO, ¶m); + } if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags)) ivtv_pio_work_handler(itv); @@ -684,34 +691,14 @@ static void ivtv_irq_enc_start_cap(struct ivtv *itv) static void ivtv_irq_enc_vbi_cap(struct ivtv *itv) { - struct ivtv_stream *s_mpg = &itv->streams[IVTV_ENC_STREAM_TYPE_MPG]; u32 data[CX2341X_MBOX_MAX_DATA]; struct ivtv_stream *s; IVTV_DEBUG_HI_IRQ("ENC START VBI CAP\n"); s = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; - /* If more than two VBI buffers are pending, then - clear the old ones and start with this new one. - This can happen during transition stages when MPEG capturing is - started, but the first interrupts haven't arrived yet. During - that period VBI requests can accumulate without being able to - DMA the data. Since at most four VBI DMA buffers are available, - we just drop the old requests when there are already three - requests queued. */ - if (s->sg_pending_size > 2) { - struct ivtv_buffer *buf; - list_for_each_entry(buf, &s->q_predma.list, list) - ivtv_buf_sync_for_cpu(s, buf); - ivtv_queue_move(s, &s->q_predma, NULL, &s->q_free, 0); - s->sg_pending_size = 0; - } - /* if we can append the data, and the MPEG stream isn't capturing, - then start a DMA request for just the VBI data. */ - if (!stream_enc_dma_append(s, data) && - !test_bit(IVTV_F_S_STREAMING, &s_mpg->s_flags)) { + if (!stream_enc_dma_append(s, data)) set_bit(ivtv_use_pio(s) ? IVTV_F_S_PIO_PENDING : IVTV_F_S_DMA_PENDING, &s->s_flags); - } } static void ivtv_irq_dec_vbi_reinsert(struct ivtv *itv) diff --git a/linux/drivers/media/video/ivtv/ivtv-queue.h b/linux/drivers/media/video/ivtv/ivtv-queue.h index 7cfc0c9ab..476556afd 100644 --- a/linux/drivers/media/video/ivtv/ivtv-queue.h +++ b/linux/drivers/media/video/ivtv/ivtv-queue.h @@ -23,7 +23,7 @@ #define IVTV_QUEUE_H #define IVTV_DMA_UNMAPPED ((u32) -1) -#define SLICED_VBI_PIO 1 +#define SLICED_VBI_PIO 0 /* ivtv_buffer utility functions */ diff --git a/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c index b883c4e08..730e85d86 100644 --- a/linux/drivers/media/video/ivtv/ivtv-streams.c +++ b/linux/drivers/media/video/ivtv/ivtv-streams.c @@ -208,11 +208,6 @@ static int ivtv_prep_dev(struct ivtv *itv, int type) return -ENOMEM; } - s->v4l2dev->type = VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT | - VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER; - if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) { - s->v4l2dev->type |= VID_TYPE_MPEG_DECODER; - } snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "ivtv%d %s", itv->num, s->name); @@ -368,7 +363,7 @@ static void ivtv_vbi_setup(struct ivtv *itv) /* Every X number of frames a VBI interrupt arrives (frames as in 25 or 30 fps) */ data[1] = 1; /* The VBI frames are stored in a ringbuffer with this size (with a VBI frame as unit) */ - data[2] = raw ? 4 : 8; + data[2] = raw ? 4 : 4 * (itv->vbi.raw_size / itv->vbi.enc_size); /* The start/stop codes determine which VBI lines end up in the raw VBI data area. The codes are from table 24 in the saa7115 datasheet. Each raw/sliced/video line is framed with codes FF0000XX where XX is the SAV/EAV (Start/End of Active Video) diff --git a/linux/drivers/media/video/ivtv/ivtv-vbi.c b/linux/drivers/media/video/ivtv/ivtv-vbi.c index 71798f0da..1ce9deb11 100644 --- a/linux/drivers/media/video/ivtv/ivtv-vbi.c +++ b/linux/drivers/media/video/ivtv/ivtv-vbi.c @@ -293,6 +293,7 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 u32 line_size = itv->vbi.sliced_decoder_line_size; struct v4l2_decode_vbi_line vbi; int i; + unsigned lines = 0; /* find the first valid line */ for (i = 0; i < size; i++, buf++) { @@ -313,7 +314,8 @@ static u32 compress_sliced_buf(struct ivtv *itv, u32 line, u8 *buf, u32 size, u8 } vbi.p = p + 4; itv->video_dec_func(itv, VIDIOC_INT_DECODE_VBI_LINE, &vbi); - if (vbi.type) { + if (vbi.type && !(lines & (1 << vbi.line))) { + lines |= 1 << vbi.line; itv->vbi.sliced_data[line].id = vbi.type; itv->vbi.sliced_data[line].field = vbi.is_second_field; itv->vbi.sliced_data[line].line = vbi.line; diff --git a/linux/drivers/media/video/ivtv/ivtv-version.h b/linux/drivers/media/video/ivtv/ivtv-version.h index 442f43f11..8cd753d30 100644 --- a/linux/drivers/media/video/ivtv/ivtv-version.h +++ b/linux/drivers/media/video/ivtv/ivtv-version.h @@ -22,7 +22,7 @@ #define IVTV_DRIVER_NAME "ivtv" #define IVTV_DRIVER_VERSION_MAJOR 1 -#define IVTV_DRIVER_VERSION_MINOR 3 +#define IVTV_DRIVER_VERSION_MINOR 4 #define IVTV_DRIVER_VERSION_PATCHLEVEL 0 #define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL) diff --git a/linux/drivers/media/video/m52790.c b/linux/drivers/media/video/m52790.c index 87e948caf..f39da4a36 100644 --- a/linux/drivers/media/video/m52790.c +++ b/linux/drivers/media/video/m52790.c @@ -26,7 +26,7 @@ #include <asm/uaccess.h> #include <linux/i2c.h> #include <linux/i2c-id.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <media/m52790.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> diff --git a/linux/drivers/media/video/meye.c b/linux/drivers/media/video/meye.c index 4ae76d0b0..a0cdae0c1 100644 --- a/linux/drivers/media/video/meye.c +++ b/linux/drivers/media/video/meye.c @@ -850,15 +850,19 @@ static int meye_open(struct inode *inode, struct file *file) { int i, err; + lock_kernel(); err = video_exclusive_open(inode, file); - if (err < 0) + if (err < 0) { + unlock_kernel(); return err; + } mchip_hic_stop(); if (mchip_dma_alloc()) { printk(KERN_ERR "meye: mchip framebuffer allocation failed\n"); video_exclusive_release(inode, file); + unlock_kernel(); return -ENOBUFS; } @@ -866,6 +870,7 @@ static int meye_open(struct inode *inode, struct file *file) meye.grab_buffer[i].state = MEYE_BUF_UNUSED; kfifo_reset(meye.grabq); kfifo_reset(meye.doneq); + unlock_kernel(); return 0; } @@ -1703,13 +1708,7 @@ static const struct file_operations meye_fops = { .llseek = no_llseek, }; -static struct video_device meye_template = { - .owner = THIS_MODULE, - .name = "meye", - .type = VID_TYPE_CAPTURE, - .fops = &meye_fops, - .release = video_device_release, - .minor = -1, +static const struct v4l2_ioctl_ops meye_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, @@ -1730,6 +1729,14 @@ static struct video_device meye_template = { .vidioc_default = vidioc_default, }; +static struct video_device meye_template = { + .name = "meye", + .fops = &meye_fops, + .ioctl_ops = &meye_ioctl_ops, + .release = video_device_release, + .minor = -1, +}; + #ifdef CONFIG_PM static int meye_suspend(struct pci_dev *pdev, pm_message_t state) { diff --git a/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c index d67af9753..c6c0a584c 100644 --- a/linux/drivers/media/video/msp3400-driver.c +++ b/linux/drivers/media/video/msp3400-driver.c @@ -51,7 +51,6 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/i2c.h> -#include <linux/videodev.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> diff --git a/linux/drivers/media/video/msp3400-kthreads.c b/linux/drivers/media/video/msp3400-kthreads.c index ba19edac0..29c0d5cf6 100644 --- a/linux/drivers/media/video/msp3400-kthreads.c +++ b/linux/drivers/media/video/msp3400-kthreads.c @@ -27,7 +27,6 @@ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) #include <linux/freezer.h> #endif -#include <linux/videodev.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/msp3400.h> diff --git a/linux/drivers/media/video/mt9m001.c b/linux/drivers/media/video/mt9m001.c index f4742936c..228183c54 100644 --- a/linux/drivers/media/video/mt9m001.c +++ b/linux/drivers/media/video/mt9m001.c @@ -117,24 +117,51 @@ static int reg_clear(struct soc_camera_device *icd, const u8 reg, static int mt9m001_init(struct soc_camera_device *icd) { + struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct soc_camera_link *icl = mt9m001->client->dev.platform_data; int ret; - /* Disable chip, synchronous option update */ dev_dbg(icd->vdev->parent, "%s\n", __func__); - ret = reg_write(icd, MT9M001_RESET, 1); - if (ret >= 0) - ret = reg_write(icd, MT9M001_RESET, 0); - if (ret >= 0) + if (icl->power) { + ret = icl->power(&mt9m001->client->dev, 1); + if (ret < 0) { + dev_err(icd->vdev->parent, + "Platform failed to power-on the camera.\n"); + return ret; + } + } + + /* The camera could have been already on, we reset it additionally */ + if (icl->reset) + ret = icl->reset(&mt9m001->client->dev); + else + ret = -ENODEV; + + if (ret < 0) { + /* Either no platform reset, or platform reset failed */ + ret = reg_write(icd, MT9M001_RESET, 1); + if (!ret) + ret = reg_write(icd, MT9M001_RESET, 0); + } + /* Disable chip, synchronous option update */ + if (!ret) ret = reg_write(icd, MT9M001_OUTPUT_CONTROL, 0); - return ret >= 0 ? 0 : -EIO; + return ret; } static int mt9m001_release(struct soc_camera_device *icd) { + struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd); + struct soc_camera_link *icl = mt9m001->client->dev.platform_data; + /* Disable the chip */ reg_write(icd, MT9M001_OUTPUT_CONTROL, 0); + + if (icl->power) + icl->power(&mt9m001->client->dev, 0); + return 0; } @@ -267,24 +294,24 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd, /* Blanking and start values - default... */ ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank); - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank); /* The caller provides a supported format, as verified per * call to icd->try_fmt_cap() */ - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9M001_COLUMN_START, rect->left); - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9M001_ROW_START, rect->top); - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9M001_WINDOW_WIDTH, rect->width - 1); - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9M001_WINDOW_HEIGHT, rect->height + icd->y_skip_top - 1); - if (ret >= 0 && mt9m001->autoexposure) { + if (!ret && mt9m001->autoexposure) { ret = reg_write(icd, MT9M001_SHUTTER_WIDTH, rect->height + icd->y_skip_top + vblank); - if (ret >= 0) { + if (!ret) { const struct v4l2_queryctrl *qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE); @@ -295,7 +322,7 @@ static int mt9m001_set_fmt_cap(struct soc_camera_device *icd, } } - return ret < 0 ? ret : 0; + return ret; } static int mt9m001_try_fmt_cap(struct soc_camera_device *icd, diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c new file mode 100644 index 000000000..4844486d7 --- /dev/null +++ b/linux/drivers/media/video/mt9m111.c @@ -0,0 +1,973 @@ +/* + * Driver for MT9M111 CMOS Image Sensor from Micron + * + * Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/videodev2.h> +#include <linux/slab.h> +#include <linux/i2c.h> +#include <linux/log2.h> +#include <linux/gpio.h> +#include <linux/delay.h> + +#include <media/v4l2-common.h> +#include <media/v4l2-chip-ident.h> +#include <media/soc_camera.h> + +/* + * mt9m111 i2c address is 0x5d or 0x48 (depending on SAddr pin) + * The platform has to define i2c_board_info and call i2c_register_board_info() + */ + +/* mt9m111: Sensor register addresses */ +#define MT9M111_CHIP_VERSION 0x000 +#define MT9M111_ROW_START 0x001 +#define MT9M111_COLUMN_START 0x002 +#define MT9M111_WINDOW_HEIGHT 0x003 +#define MT9M111_WINDOW_WIDTH 0x004 +#define MT9M111_HORIZONTAL_BLANKING_B 0x005 +#define MT9M111_VERTICAL_BLANKING_B 0x006 +#define MT9M111_HORIZONTAL_BLANKING_A 0x007 +#define MT9M111_VERTICAL_BLANKING_A 0x008 +#define MT9M111_SHUTTER_WIDTH 0x009 +#define MT9M111_ROW_SPEED 0x00a +#define MT9M111_EXTRA_DELAY 0x00b +#define MT9M111_SHUTTER_DELAY 0x00c +#define MT9M111_RESET 0x00d +#define MT9M111_READ_MODE_B 0x020 +#define MT9M111_READ_MODE_A 0x021 +#define MT9M111_FLASH_CONTROL 0x023 +#define MT9M111_GREEN1_GAIN 0x02b +#define MT9M111_BLUE_GAIN 0x02c +#define MT9M111_RED_GAIN 0x02d +#define MT9M111_GREEN2_GAIN 0x02e +#define MT9M111_GLOBAL_GAIN 0x02f +#define MT9M111_CONTEXT_CONTROL 0x0c8 +#define MT9M111_PAGE_MAP 0x0f0 +#define MT9M111_BYTE_WISE_ADDR 0x0f1 + +#define MT9M111_RESET_SYNC_CHANGES (1 << 15) +#define MT9M111_RESET_RESTART_BAD_FRAME (1 << 9) +#define MT9M111_RESET_SHOW_BAD_FRAMES (1 << 8) +#define MT9M111_RESET_RESET_SOC (1 << 5) +#define MT9M111_RESET_OUTPUT_DISABLE (1 << 4) +#define MT9M111_RESET_CHIP_ENABLE (1 << 3) +#define MT9M111_RESET_ANALOG_STANDBY (1 << 2) +#define MT9M111_RESET_RESTART_FRAME (1 << 1) +#define MT9M111_RESET_RESET_MODE (1 << 0) + +#define MT9M111_RMB_MIRROR_COLS (1 << 1) +#define MT9M111_RMB_MIRROR_ROWS (1 << 0) +#define MT9M111_CTXT_CTRL_RESTART (1 << 15) +#define MT9M111_CTXT_CTRL_DEFECTCOR_B (1 << 12) +#define MT9M111_CTXT_CTRL_RESIZE_B (1 << 10) +#define MT9M111_CTXT_CTRL_CTRL2_B (1 << 9) +#define MT9M111_CTXT_CTRL_GAMMA_B (1 << 8) +#define MT9M111_CTXT_CTRL_XENON_EN (1 << 7) +#define MT9M111_CTXT_CTRL_READ_MODE_B (1 << 3) +#define MT9M111_CTXT_CTRL_LED_FLASH_EN (1 << 2) +#define MT9M111_CTXT_CTRL_VBLANK_SEL_B (1 << 1) +#define MT9M111_CTXT_CTRL_HBLANK_SEL_B (1 << 0) +/* + * mt9m111: Colorpipe register addresses (0x100..0x1ff) + */ +#define MT9M111_OPER_MODE_CTRL 0x106 +#define MT9M111_OUTPUT_FORMAT_CTRL 0x108 +#define MT9M111_REDUCER_XZOOM_B 0x1a0 +#define MT9M111_REDUCER_XSIZE_B 0x1a1 +#define MT9M111_REDUCER_YZOOM_B 0x1a3 +#define MT9M111_REDUCER_YSIZE_B 0x1a4 +#define MT9M111_REDUCER_XZOOM_A 0x1a6 +#define MT9M111_REDUCER_XSIZE_A 0x1a7 +#define MT9M111_REDUCER_YZOOM_A 0x1a9 +#define MT9M111_REDUCER_YSIZE_A 0x1aa + +#define MT9M111_OUTPUT_FORMAT_CTRL2_A 0x13a +#define MT9M111_OUTPUT_FORMAT_CTRL2_B 0x19b + +#define MT9M111_OPMODE_AUTOEXPO_EN (1 << 14) + + +#define MT9M111_OUTFMT_PROCESSED_BAYER (1 << 14) +#define MT9M111_OUTFMT_BYPASS_IFP (1 << 10) +#define MT9M111_OUTFMT_INV_PIX_CLOCK (1 << 9) +#define MT9M111_OUTFMT_RGB (1 << 8) +#define MT9M111_OUTFMT_RGB565 (0x0 << 6) +#define MT9M111_OUTFMT_RGB555 (0x1 << 6) +#define MT9M111_OUTFMT_RGB444x (0x2 << 6) +#define MT9M111_OUTFMT_RGBx444 (0x3 << 6) +#define MT9M111_OUTFMT_TST_RAMP_OFF (0x0 << 4) +#define MT9M111_OUTFMT_TST_RAMP_COL (0x1 << 4) +#define MT9M111_OUTFMT_TST_RAMP_ROW (0x2 << 4) +#define MT9M111_OUTFMT_TST_RAMP_FRAME (0x3 << 4) +#define MT9M111_OUTFMT_SHIFT_3_UP (1 << 3) +#define MT9M111_OUTFMT_AVG_CHROMA (1 << 2) +#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y (1 << 1) +#define MT9M111_OUTFMT_SWAP_RGB_EVEN (1 << 1) +#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr (1 << 0) +/* + * mt9m111: Camera control register addresses (0x200..0x2ff not implemented) + */ + +#define reg_read(reg) mt9m111_reg_read(icd, MT9M111_##reg) +#define reg_write(reg, val) mt9m111_reg_write(icd, MT9M111_##reg, (val)) +#define reg_set(reg, val) mt9m111_reg_set(icd, MT9M111_##reg, (val)) +#define reg_clear(reg, val) mt9m111_reg_clear(icd, MT9M111_##reg, (val)) + +#define MT9M111_MIN_DARK_ROWS 8 +#define MT9M111_MIN_DARK_COLS 24 +#define MT9M111_MAX_HEIGHT 1024 +#define MT9M111_MAX_WIDTH 1280 + +#define COL_FMT(_name, _depth, _fourcc, _colorspace) \ + { .name = _name, .depth = _depth, .fourcc = _fourcc, \ + .colorspace = _colorspace } +#define RGB_FMT(_name, _depth, _fourcc) \ + COL_FMT(_name, _depth, _fourcc, V4L2_COLORSPACE_SRGB) + +static const struct soc_camera_data_format mt9m111_colour_formats[] = { + COL_FMT("YCrYCb 8 bit", 8, V4L2_PIX_FMT_YUYV, V4L2_COLORSPACE_JPEG), + RGB_FMT("RGB 565", 16, V4L2_PIX_FMT_RGB565), + RGB_FMT("RGB 555", 16, V4L2_PIX_FMT_RGB555), + RGB_FMT("Bayer (sRGB) 10 bit", 10, V4L2_PIX_FMT_SBGGR16), + RGB_FMT("Bayer (sRGB) 8 bit", 8, V4L2_PIX_FMT_SBGGR8), +}; + +enum mt9m111_context { + HIGHPOWER = 0, + LOWPOWER, +}; + +struct mt9m111 { + struct i2c_client *client; + struct soc_camera_device icd; + int model; /* V4L2_IDENT_MT9M111* codes from v4l2-chip-ident.h */ + enum mt9m111_context context; + unsigned int left, top, width, height; + u32 pixfmt; + unsigned char autoexposure; + unsigned char datawidth; + unsigned int powered:1; + unsigned int hflip:1; + unsigned int vflip:1; + unsigned int swap_rgb_even_odd:1; + unsigned int swap_rgb_red_blue:1; + unsigned int swap_yuv_y_chromas:1; + unsigned int swap_yuv_cb_cr:1; +}; + +static int reg_page_map_set(struct i2c_client *client, const u16 reg) +{ + int ret; + u16 page; + static int lastpage = -1; /* PageMap cache value */ + + page = (reg >> 8); + if (page == lastpage) + return 0; + if (page > 2) + return -EINVAL; + + ret = i2c_smbus_write_word_data(client, MT9M111_PAGE_MAP, swab16(page)); + if (!ret) + lastpage = page; + return ret; +} + +static int mt9m111_reg_read(struct soc_camera_device *icd, const u16 reg) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + struct i2c_client *client = mt9m111->client; + int ret; + + ret = reg_page_map_set(client, reg); + if (!ret) + ret = swab16(i2c_smbus_read_word_data(client, (reg & 0xff))); + + dev_dbg(&icd->dev, "read reg.%03x -> %04x\n", reg, ret); + return ret; +} + +static int mt9m111_reg_write(struct soc_camera_device *icd, const u16 reg, + const u16 data) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + struct i2c_client *client = mt9m111->client; + int ret; + + ret = reg_page_map_set(client, reg); + if (!ret) + ret = i2c_smbus_write_word_data(mt9m111->client, (reg & 0xff), + swab16(data)); + dev_dbg(&icd->dev, "write reg.%03x = %04x -> %d\n", reg, data, ret); + return ret; +} + +static int mt9m111_reg_set(struct soc_camera_device *icd, const u16 reg, + const u16 data) +{ + int ret; + + ret = mt9m111_reg_read(icd, reg); + if (ret >= 0) + ret = mt9m111_reg_write(icd, reg, ret | data); + return ret; +} + +static int mt9m111_reg_clear(struct soc_camera_device *icd, const u16 reg, + const u16 data) +{ + int ret; + + ret = mt9m111_reg_read(icd, reg); + return mt9m111_reg_write(icd, reg, ret & ~data); +} + +static int mt9m111_set_context(struct soc_camera_device *icd, + enum mt9m111_context ctxt) +{ + int valB = MT9M111_CTXT_CTRL_RESTART | MT9M111_CTXT_CTRL_DEFECTCOR_B + | MT9M111_CTXT_CTRL_RESIZE_B | MT9M111_CTXT_CTRL_CTRL2_B + | MT9M111_CTXT_CTRL_GAMMA_B | MT9M111_CTXT_CTRL_READ_MODE_B + | MT9M111_CTXT_CTRL_VBLANK_SEL_B + | MT9M111_CTXT_CTRL_HBLANK_SEL_B; + int valA = MT9M111_CTXT_CTRL_RESTART; + + if (ctxt == HIGHPOWER) + return reg_write(CONTEXT_CONTROL, valB); + else + return reg_write(CONTEXT_CONTROL, valA); +} + +static int mt9m111_setup_rect(struct soc_camera_device *icd) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + int ret, is_raw_format; + int width = mt9m111->width; + int height = mt9m111->height; + + if ((mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR8) + || (mt9m111->pixfmt == V4L2_PIX_FMT_SBGGR16)) + is_raw_format = 1; + else + is_raw_format = 0; + + ret = reg_write(COLUMN_START, mt9m111->left); + if (!ret) + ret = reg_write(ROW_START, mt9m111->top); + + if (is_raw_format) { + if (!ret) + ret = reg_write(WINDOW_WIDTH, width); + if (!ret) + ret = reg_write(WINDOW_HEIGHT, height); + } else { + if (!ret) + ret = reg_write(REDUCER_XZOOM_B, MT9M111_MAX_WIDTH); + if (!ret) + ret = reg_write(REDUCER_YZOOM_B, MT9M111_MAX_HEIGHT); + if (!ret) + ret = reg_write(REDUCER_XSIZE_B, width); + if (!ret) + ret = reg_write(REDUCER_YSIZE_B, height); + if (!ret) + ret = reg_write(REDUCER_XZOOM_A, MT9M111_MAX_WIDTH); + if (!ret) + ret = reg_write(REDUCER_YZOOM_A, MT9M111_MAX_HEIGHT); + if (!ret) + ret = reg_write(REDUCER_XSIZE_A, width); + if (!ret) + ret = reg_write(REDUCER_YSIZE_A, height); + } + + return ret; +} + +static int mt9m111_setup_pixfmt(struct soc_camera_device *icd, u16 outfmt) +{ + int ret; + + ret = reg_write(OUTPUT_FORMAT_CTRL2_A, outfmt); + if (!ret) + ret = reg_write(OUTPUT_FORMAT_CTRL2_B, outfmt); + return ret; +} + +static int mt9m111_setfmt_bayer8(struct soc_camera_device *icd) +{ + return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_PROCESSED_BAYER); +} + +static int mt9m111_setfmt_bayer10(struct soc_camera_device *icd) +{ + return mt9m111_setup_pixfmt(icd, MT9M111_OUTFMT_BYPASS_IFP); +} + +static int mt9m111_setfmt_rgb565(struct soc_camera_device *icd) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + int val = 0; + + if (mt9m111->swap_rgb_red_blue) + val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; + if (mt9m111->swap_rgb_even_odd) + val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; + val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565; + + return mt9m111_setup_pixfmt(icd, val); +} + +static int mt9m111_setfmt_rgb555(struct soc_camera_device *icd) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + int val = 0; + + if (mt9m111->swap_rgb_red_blue) + val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; + if (mt9m111->swap_rgb_even_odd) + val |= MT9M111_OUTFMT_SWAP_RGB_EVEN; + val |= MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555; + + return mt9m111_setup_pixfmt(icd, val); +} + +static int mt9m111_setfmt_yuv(struct soc_camera_device *icd) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + int val = 0; + + if (mt9m111->swap_yuv_cb_cr) + val |= MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr; + if (mt9m111->swap_yuv_y_chromas) + val |= MT9M111_OUTFMT_SWAP_YCbCr_C_Y; + + return mt9m111_setup_pixfmt(icd, val); +} + +static int mt9m111_enable(struct soc_camera_device *icd) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + struct soc_camera_link *icl = mt9m111->client->dev.platform_data; + int ret; + + if (icl->power) { + ret = icl->power(&mt9m111->client->dev, 1); + if (ret < 0) { + dev_err(icd->vdev->parent, + "Platform failed to power-on the camera.\n"); + return ret; + } + } + + ret = reg_set(RESET, MT9M111_RESET_CHIP_ENABLE); + if (!ret) + mt9m111->powered = 1; + return ret; +} + +static int mt9m111_disable(struct soc_camera_device *icd) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + struct soc_camera_link *icl = mt9m111->client->dev.platform_data; + int ret; + + ret = reg_clear(RESET, MT9M111_RESET_CHIP_ENABLE); + if (!ret) + mt9m111->powered = 0; + + if (icl->power) + icl->power(&mt9m111->client->dev, 0); + + return ret; +} + +static int mt9m111_reset(struct soc_camera_device *icd) +{ + int ret; + + ret = reg_set(RESET, MT9M111_RESET_RESET_MODE); + if (!ret) + ret = reg_set(RESET, MT9M111_RESET_RESET_SOC); + if (!ret) + ret = reg_clear(RESET, MT9M111_RESET_RESET_MODE + | MT9M111_RESET_RESET_SOC); + return ret; +} + +static int mt9m111_start_capture(struct soc_camera_device *icd) +{ + return 0; +} + +static int mt9m111_stop_capture(struct soc_camera_device *icd) +{ + return 0; +} + +static unsigned long mt9m111_query_bus_param(struct soc_camera_device *icd) +{ + return SOCAM_MASTER | SOCAM_PCLK_SAMPLE_RISING | + SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | + SOCAM_DATAWIDTH_8; +} + +static int mt9m111_set_bus_param(struct soc_camera_device *icd, unsigned long f) +{ + return 0; +} + +static int mt9m111_set_pixfmt(struct soc_camera_device *icd, u32 pixfmt) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + int ret; + + switch (pixfmt) { + case V4L2_PIX_FMT_SBGGR8: + ret = mt9m111_setfmt_bayer8(icd); + break; + case V4L2_PIX_FMT_SBGGR16: + ret = mt9m111_setfmt_bayer10(icd); + break; + case V4L2_PIX_FMT_RGB555: + ret = mt9m111_setfmt_rgb555(icd); + break; + case V4L2_PIX_FMT_RGB565: + ret = mt9m111_setfmt_rgb565(icd); + break; + case V4L2_PIX_FMT_YUYV: + ret = mt9m111_setfmt_yuv(icd); + break; + default: + dev_err(&icd->dev, "Pixel format not handled : %x\n", pixfmt); + ret = -EINVAL; + } + + if (!ret) + mt9m111->pixfmt = pixfmt; + + return ret; +} + +static int mt9m111_set_fmt_cap(struct soc_camera_device *icd, + __u32 pixfmt, struct v4l2_rect *rect) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + int ret; + + mt9m111->left = rect->left; + mt9m111->top = rect->top; + mt9m111->width = rect->width; + mt9m111->height = rect->height; + + dev_dbg(&icd->dev, "%s fmt=%x left=%d, top=%d, width=%d, height=%d\n", + __func__, pixfmt, mt9m111->left, mt9m111->top, mt9m111->width, + mt9m111->height); + + ret = mt9m111_setup_rect(icd); + if (!ret) + ret = mt9m111_set_pixfmt(icd, pixfmt); + return ret; +} + +static int mt9m111_try_fmt_cap(struct soc_camera_device *icd, + struct v4l2_format *f) +{ + if (f->fmt.pix.height > MT9M111_MAX_HEIGHT) + f->fmt.pix.height = MT9M111_MAX_HEIGHT; + if (f->fmt.pix.width > MT9M111_MAX_WIDTH) + f->fmt.pix.width = MT9M111_MAX_WIDTH; + + return 0; +} + +static int mt9m111_get_chip_id(struct soc_camera_device *icd, + struct v4l2_chip_ident *id) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + + if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR) + return -EINVAL; + + if (id->match_chip != mt9m111->client->addr) + return -ENODEV; + + id->ident = mt9m111->model; + id->revision = 0; + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static int mt9m111_get_register(struct soc_camera_device *icd, + struct v4l2_register *reg) +{ + int val; + + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + + if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) + return -EINVAL; + if (reg->match_chip != mt9m111->client->addr) + return -ENODEV; + + val = mt9m111_reg_read(icd, reg->reg); + reg->val = (u64)val; + + if (reg->val > 0xffff) + return -EIO; + + return 0; +} + +static int mt9m111_set_register(struct soc_camera_device *icd, + struct v4l2_register *reg) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + + if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff) + return -EINVAL; + + if (reg->match_chip != mt9m111->client->addr) + return -ENODEV; + + if (mt9m111_reg_write(icd, reg->reg, reg->val) < 0) + return -EIO; + + return 0; +} +#endif + +static const struct v4l2_queryctrl mt9m111_controls[] = { + { + .id = V4L2_CID_VFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Verticaly", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { + .id = V4L2_CID_HFLIP, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Flip Horizontaly", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0, + }, { /* gain = 1/32*val (=>gain=1 if val==32) */ + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, + .maximum = 63 * 2 * 2, + .step = 1, + .default_value = 32, + .flags = V4L2_CTRL_FLAG_SLIDER, + }, { + .id = V4L2_CID_EXPOSURE_AUTO, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Auto Exposure", + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 1, + } +}; + +static int mt9m111_video_probe(struct soc_camera_device *); +static void mt9m111_video_remove(struct soc_camera_device *); +static int mt9m111_get_control(struct soc_camera_device *, + struct v4l2_control *); +static int mt9m111_set_control(struct soc_camera_device *, + struct v4l2_control *); +static int mt9m111_resume(struct soc_camera_device *icd); +static int mt9m111_init(struct soc_camera_device *icd); +static int mt9m111_release(struct soc_camera_device *icd); + +static struct soc_camera_ops mt9m111_ops = { + .owner = THIS_MODULE, + .probe = mt9m111_video_probe, + .remove = mt9m111_video_remove, + .init = mt9m111_init, + .resume = mt9m111_resume, + .release = mt9m111_release, + .start_capture = mt9m111_start_capture, + .stop_capture = mt9m111_stop_capture, + .set_fmt_cap = mt9m111_set_fmt_cap, + .try_fmt_cap = mt9m111_try_fmt_cap, + .query_bus_param = mt9m111_query_bus_param, + .set_bus_param = mt9m111_set_bus_param, + .controls = mt9m111_controls, + .num_controls = ARRAY_SIZE(mt9m111_controls), + .get_control = mt9m111_get_control, + .set_control = mt9m111_set_control, + .get_chip_id = mt9m111_get_chip_id, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .get_register = mt9m111_get_register, + .set_register = mt9m111_set_register, +#endif +}; + +static int mt9m111_set_flip(struct soc_camera_device *icd, int flip, int mask) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + int ret; + + if (mt9m111->context == HIGHPOWER) { + if (flip) + ret = reg_set(READ_MODE_B, mask); + else + ret = reg_clear(READ_MODE_B, mask); + } else { + if (flip) + ret = reg_set(READ_MODE_A, mask); + else + ret = reg_clear(READ_MODE_A, mask); + } + + return ret; +} + +static int mt9m111_get_global_gain(struct soc_camera_device *icd) +{ + unsigned int data, gain; + + data = reg_read(GLOBAL_GAIN); + if (data >= 0) + gain = ((data & (1 << 10)) * 2) + | ((data & (1 << 9)) * 2) + | (data & 0x2f); + else + gain = data; + + return gain; +} +static int mt9m111_set_global_gain(struct soc_camera_device *icd, int gain) +{ + u16 val; + + if (gain > 63 * 2 * 2) + return -EINVAL; + + icd->gain = gain; + if ((gain >= 64 * 2) && (gain < 63 * 2 * 2)) + val = (1 << 10) | (1 << 9) | (gain / 4); + else if ((gain >= 64) && (gain < 64 * 2)) + val = (1 << 9) | (gain / 2); + else + val = gain; + + return reg_write(GLOBAL_GAIN, val); +} + +static int mt9m111_set_autoexposure(struct soc_camera_device *icd, int on) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + int ret; + + if (on) + ret = reg_set(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); + else + ret = reg_clear(OPER_MODE_CTRL, MT9M111_OPMODE_AUTOEXPO_EN); + + if (!ret) + mt9m111->autoexposure = on; + + return ret; +} +static int mt9m111_get_control(struct soc_camera_device *icd, + struct v4l2_control *ctrl) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + int data; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + if (mt9m111->context == HIGHPOWER) + data = reg_read(READ_MODE_B); + else + data = reg_read(READ_MODE_A); + + if (data < 0) + return -EIO; + ctrl->value = !!(data & MT9M111_RMB_MIRROR_ROWS); + break; + case V4L2_CID_HFLIP: + if (mt9m111->context == HIGHPOWER) + data = reg_read(READ_MODE_B); + else + data = reg_read(READ_MODE_A); + + if (data < 0) + return -EIO; + ctrl->value = !!(data & MT9M111_RMB_MIRROR_COLS); + break; + case V4L2_CID_GAIN: + data = mt9m111_get_global_gain(icd); + if (data < 0) + return data; + ctrl->value = data; + break; + case V4L2_CID_EXPOSURE_AUTO: + ctrl->value = mt9m111->autoexposure; + break; + } + return 0; +} + +static int mt9m111_set_control(struct soc_camera_device *icd, + struct v4l2_control *ctrl) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + const struct v4l2_queryctrl *qctrl; + int ret; + + qctrl = soc_camera_find_qctrl(&mt9m111_ops, ctrl->id); + + if (!qctrl) + return -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_VFLIP: + mt9m111->vflip = ctrl->value; + ret = mt9m111_set_flip(icd, ctrl->value, + MT9M111_RMB_MIRROR_ROWS); + break; + case V4L2_CID_HFLIP: + mt9m111->hflip = ctrl->value; + ret = mt9m111_set_flip(icd, ctrl->value, + MT9M111_RMB_MIRROR_COLS); + break; + case V4L2_CID_GAIN: + ret = mt9m111_set_global_gain(icd, ctrl->value); + break; + case V4L2_CID_EXPOSURE_AUTO: + ret = mt9m111_set_autoexposure(icd, ctrl->value); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +int mt9m111_restore_state(struct soc_camera_device *icd) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + + mt9m111_set_context(icd, mt9m111->context); + mt9m111_set_pixfmt(icd, mt9m111->pixfmt); + mt9m111_setup_rect(icd); + mt9m111_set_flip(icd, mt9m111->hflip, MT9M111_RMB_MIRROR_COLS); + mt9m111_set_flip(icd, mt9m111->vflip, MT9M111_RMB_MIRROR_ROWS); + mt9m111_set_global_gain(icd, icd->gain); + mt9m111_set_autoexposure(icd, mt9m111->autoexposure); + return 0; +} + +static int mt9m111_resume(struct soc_camera_device *icd) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + int ret = 0; + + if (mt9m111->powered) { + ret = mt9m111_enable(icd); + if (!ret) + ret = mt9m111_reset(icd); + if (!ret) + ret = mt9m111_restore_state(icd); + } + return ret; +} + +static int mt9m111_init(struct soc_camera_device *icd) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + int ret; + + mt9m111->context = HIGHPOWER; + ret = mt9m111_enable(icd); + if (!ret) + ret = mt9m111_reset(icd); + if (!ret) + ret = mt9m111_set_context(icd, mt9m111->context); + if (!ret) + ret = mt9m111_set_autoexposure(icd, mt9m111->autoexposure); + if (ret) + dev_err(&icd->dev, "mt9m111 init failed: %d\n", ret); + return ret; +} + +static int mt9m111_release(struct soc_camera_device *icd) +{ + int ret; + + ret = mt9m111_disable(icd); + if (ret < 0) + dev_err(&icd->dev, "mt9m111 release failed: %d\n", ret); + + return ret; +} + +/* + * Interface active, can use i2c. If it fails, it can indeed mean, that + * this wasn't our capture interface, so, we wait for the right one + */ +static int mt9m111_video_probe(struct soc_camera_device *icd) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + s32 data; + int ret; + + /* + * We must have a parent by now. And it cannot be a wrong one. + * So this entire test is completely redundant. + */ + if (!icd->dev.parent || + to_soc_camera_host(icd->dev.parent)->nr != icd->iface) + return -ENODEV; + + ret = mt9m111_enable(icd); + if (ret) + goto ei2c; + ret = mt9m111_reset(icd); + if (ret) + goto ei2c; + + data = reg_read(CHIP_VERSION); + + switch (data) { + case 0x143a: + mt9m111->model = V4L2_IDENT_MT9M111; + icd->formats = mt9m111_colour_formats; + icd->num_formats = ARRAY_SIZE(mt9m111_colour_formats); + break; + default: + ret = -ENODEV; + dev_err(&icd->dev, + "No MT9M111 chip detected, register read %x\n", data); + goto ei2c; + } + + dev_info(&icd->dev, "Detected a MT9M111 chip ID 0x143a\n"); + + ret = soc_camera_video_start(icd); + if (ret) + goto eisis; + + mt9m111->autoexposure = 1; + + mt9m111->swap_rgb_even_odd = 1; + mt9m111->swap_rgb_red_blue = 1; + + return 0; +eisis: +ei2c: + return ret; +} + +static void mt9m111_video_remove(struct soc_camera_device *icd) +{ + struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); + + dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m111->client->addr, + mt9m111->icd.dev.parent, mt9m111->icd.vdev); + soc_camera_video_stop(&mt9m111->icd); +} + +static int mt9m111_probe(struct i2c_client *client, + const struct i2c_device_id *did) +{ + struct mt9m111 *mt9m111; + struct soc_camera_device *icd; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct soc_camera_link *icl = client->dev.platform_data; + int ret; + + if (!icl) { + dev_err(&client->dev, "MT9M111 driver needs platform data\n"); + return -EINVAL; + } + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) { + dev_warn(&adapter->dev, + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n"); + return -EIO; + } + + mt9m111 = kzalloc(sizeof(struct mt9m111), GFP_KERNEL); + if (!mt9m111) + return -ENOMEM; + + mt9m111->client = client; + i2c_set_clientdata(client, mt9m111); + + /* Second stage probe - when a capture adapter is there */ + icd = &mt9m111->icd; + icd->ops = &mt9m111_ops; + icd->control = &client->dev; + icd->x_min = MT9M111_MIN_DARK_COLS; + icd->y_min = MT9M111_MIN_DARK_ROWS; + icd->x_current = icd->x_min; + icd->y_current = icd->y_min; + icd->width_min = MT9M111_MIN_DARK_ROWS; + icd->width_max = MT9M111_MAX_WIDTH; + icd->height_min = MT9M111_MIN_DARK_COLS; + icd->height_max = MT9M111_MAX_HEIGHT; + icd->y_skip_top = 0; + icd->iface = icl->bus_id; + + ret = soc_camera_device_register(icd); + if (ret) + goto eisdr; + return 0; + +eisdr: + kfree(mt9m111); + return ret; +} + +static int mt9m111_remove(struct i2c_client *client) +{ + struct mt9m111 *mt9m111 = i2c_get_clientdata(client); + soc_camera_device_unregister(&mt9m111->icd); + kfree(mt9m111); + + return 0; +} + +static const struct i2c_device_id mt9m111_id[] = { + { "mt9m111", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mt9m111_id); + +static struct i2c_driver mt9m111_i2c_driver = { + .driver = { + .name = "mt9m111", + }, + .probe = mt9m111_probe, + .remove = mt9m111_remove, + .id_table = mt9m111_id, +}; + +static int __init mt9m111_mod_init(void) +{ + return i2c_add_driver(&mt9m111_i2c_driver); +} + +static void __exit mt9m111_mod_exit(void) +{ + i2c_del_driver(&mt9m111_i2c_driver); +} + +module_init(mt9m111_mod_init); +module_exit(mt9m111_mod_exit); + +MODULE_DESCRIPTION("Micron MT9M111 Camera driver"); +MODULE_AUTHOR("Robert Jarzmik"); +MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c index 1ff36edd7..0320d006f 100644 --- a/linux/drivers/media/video/mt9v022.c +++ b/linux/drivers/media/video/mt9v022.c @@ -134,34 +134,56 @@ static int reg_clear(struct soc_camera_device *icd, const u8 reg, static int mt9v022_init(struct soc_camera_device *icd) { struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); + struct soc_camera_link *icl = mt9v022->client->dev.platform_data; int ret; + if (icl->power) { + ret = icl->power(&mt9v022->client->dev, 1); + if (ret < 0) { + dev_err(icd->vdev->parent, + "Platform failed to power-on the camera.\n"); + return ret; + } + } + + /* + * The camera could have been already on, we hard-reset it additionally, + * if available. Soft reset is done in video_probe(). + */ + if (icl->reset) + icl->reset(&mt9v022->client->dev); + /* Almost the default mode: master, parallel, simultaneous, and an * undocumented bit 0x200, which is present in table 7, but not in 8, * plus snapshot mode to disable scan for now */ mt9v022->chip_control |= 0x10; ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control); - if (ret >= 0) - reg_write(icd, MT9V022_READ_MODE, 0x300); + if (!ret) + ret = reg_write(icd, MT9V022_READ_MODE, 0x300); /* All defaults */ - if (ret >= 0) + if (!ret) /* AEC, AGC on */ ret = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x3); - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480); - if (ret >= 0) + if (!ret) /* default - auto */ ret = reg_clear(icd, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1); - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9V022_DIGITAL_TEST_PATTERN, 0); - return ret >= 0 ? 0 : -EIO; + return ret; } static int mt9v022_release(struct soc_camera_device *icd) { - /* Nothing? */ + struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd); + struct soc_camera_link *icl = mt9v022->client->dev.platform_data; + + if (icl->power) + icl->power(&mt9v022->client->dev, 0); + return 0; } @@ -352,21 +374,21 @@ static int mt9v022_set_fmt_cap(struct soc_camera_device *icd, rect->height + icd->y_skip_top + 43); } /* Setup frame format: defaults apart from width and height */ - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9V022_COLUMN_START, rect->left); - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9V022_ROW_START, rect->top); - if (ret >= 0) + if (!ret) /* Default 94, Phytec driver says: * "width + horizontal blank >= 660" */ ret = reg_write(icd, MT9V022_HORIZONTAL_BLANKING, rect->width > 660 - 43 ? 43 : 660 - rect->width); - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9V022_VERTICAL_BLANKING, 45); - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9V022_WINDOW_WIDTH, rect->width); - if (ret >= 0) + if (!ret) ret = reg_write(icd, MT9V022_WINDOW_HEIGHT, rect->height + icd->y_skip_top); @@ -717,7 +739,7 @@ static int mt9v022_video_probe(struct soc_camera_device *icd) icd->num_formats = 1; } - if (ret >= 0) + if (!ret) ret = soc_camera_video_start(icd); if (ret < 0) goto eisis; diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c index bf2462a58..974505a9e 100644 --- a/linux/drivers/media/video/mxb.c +++ b/linux/drivers/media/video/mxb.c @@ -467,15 +467,15 @@ static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data /* checking for i2c-devices can be omitted here, because we already did this in "mxb_vl42_probe" */ - saa7146_vv_init(dev,&vv_data); - if( 0 != saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { + saa7146_vv_init(dev, &vv_data); + if (saa7146_register_device(&mxb->video_dev, dev, "mxb", VFL_TYPE_GRABBER)) { 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)) { + if (MXB_BOARD_CAN_DO_VBI(dev)) { + if (saa7146_register_device(&mxb->vbi_dev, dev, "mxb", VFL_TYPE_VBI)) { ERR(("cannot register vbi v4l2 device. skipping.\n")); } } @@ -487,7 +487,7 @@ static int mxb_attach(struct saa7146_dev* dev, struct saa7146_pci_extension_data i2c_use_client(mxb->saa7111a); i2c_use_client(mxb->tuner); - printk("mxb: found 'Multimedia eXtension Board'-%d.\n",mxb_num); + printk("mxb: found Multimedia eXtension Board #%d.\n", mxb_num); mxb_num++; mxb_init_done(dev); @@ -738,8 +738,8 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) DEB_EE(("VIDIOC_G_TUNER: %d\n", t->index)); memset(t,0,sizeof(*t)); - strcpy(t->name, "Television"); + strlcpy(t->name, "Television", sizeof(t->name)); t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP; t->rangelow = 772; /* 48.25 MHZ / 62.5 kHz = 772, see fi1216mk2-specs, page 2 */ @@ -747,7 +747,6 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) /* FIXME: add the real signal strength here */ t->signal = 0xffff; t->afc = 0; - mxb->tda9840->driver->command(mxb->tda9840,TDA9840_DETECT, &byte); t->audmode = mxb->cur_mode; diff --git a/linux/drivers/media/video/ov511.c b/linux/drivers/media/video/ov511.c index ebfe94076..c693b6fb0 100644 --- a/linux/drivers/media/video/ov511.c +++ b/linux/drivers/media/video/ov511.c @@ -4670,9 +4670,7 @@ static const struct file_operations ov511_fops = { }; static struct video_device vdev_template = { - .owner = THIS_MODULE, .name = "OV511 USB Camera", - .type = VID_TYPE_CAPTURE, .fops = &ov511_fops, .release = video_device_release, .minor = -1, @@ -5665,43 +5663,43 @@ static int ov_create_sysfs(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &dev_attr_custom_id); + rc = device_create_file(&vdev->dev, &dev_attr_custom_id); if (rc) goto err; - rc = video_device_create_file(vdev, &dev_attr_model); + rc = device_create_file(&vdev->dev, &dev_attr_model); if (rc) goto err_id; - rc = video_device_create_file(vdev, &dev_attr_bridge); + rc = device_create_file(&vdev->dev, &dev_attr_bridge); if (rc) goto err_model; - rc = video_device_create_file(vdev, &dev_attr_sensor); + rc = device_create_file(&vdev->dev, &dev_attr_sensor); if (rc) goto err_bridge; - rc = video_device_create_file(vdev, &dev_attr_brightness); + rc = device_create_file(&vdev->dev, &dev_attr_brightness); if (rc) goto err_sensor; - rc = video_device_create_file(vdev, &dev_attr_saturation); + rc = device_create_file(&vdev->dev, &dev_attr_saturation); if (rc) goto err_bright; - rc = video_device_create_file(vdev, &dev_attr_contrast); + rc = device_create_file(&vdev->dev, &dev_attr_contrast); if (rc) goto err_sat; - rc = video_device_create_file(vdev, &dev_attr_hue); + rc = device_create_file(&vdev->dev, &dev_attr_hue); if (rc) goto err_contrast; - rc = video_device_create_file(vdev, &dev_attr_exposure); + rc = device_create_file(&vdev->dev, &dev_attr_exposure); if (rc) goto err_hue; return 0; err_hue: - video_device_remove_file(vdev, &dev_attr_hue); + device_remove_file(&vdev->dev, &dev_attr_hue); err_contrast: - video_device_remove_file(vdev, &dev_attr_contrast); + device_remove_file(&vdev->dev, &dev_attr_contrast); err_sat: - video_device_remove_file(vdev, &dev_attr_saturation); + device_remove_file(&vdev->dev, &dev_attr_saturation); err_bright: - video_device_remove_file(vdev, &dev_attr_brightness); + device_remove_file(&vdev->dev, &dev_attr_brightness); err_sensor: - video_device_remove_file(vdev, &dev_attr_sensor); + device_remove_file(&vdev->dev, &dev_attr_sensor); err_bridge: - video_device_remove_file(vdev, &dev_attr_bridge); + device_remove_file(&vdev->dev, &dev_attr_bridge); err_model: - video_device_remove_file(vdev, &dev_attr_model); + device_remove_file(&vdev->dev, &dev_attr_model); err_id: - video_device_remove_file(vdev, &dev_attr_custom_id); + device_remove_file(&vdev->dev, &dev_attr_custom_id); err: return rc; } diff --git a/linux/drivers/media/video/planb.c b/linux/drivers/media/video/planb.c deleted file mode 100644 index 358dc2996..000000000 --- a/linux/drivers/media/video/planb.c +++ /dev/null @@ -1,2314 +0,0 @@ -/* - planb - PlanB frame grabber driver - - PlanB is used in the 7x00/8x00 series of PowerMacintosh - Computers as video input DMA controller. - - Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) - - Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) - - Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu) - - 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. -*/ - -/* $Id: planb.c,v 1.18 1999/05/02 17:36:34 mlan Exp $ */ - -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/major.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/vmalloc.h> -#include <linux/mm.h> -#include <linux/sched.h> -#include "compat.h" -#include <linux/videodev.h> -#include <media/v4l2-common.h> -#include <linux/wait.h> -#include <asm/uaccess.h> -#include <asm/io.h> -#include <asm/prom.h> -#include <asm/dbdma.h> -#include <asm/pgtable.h> -#include <asm/page.h> -#include <asm/irq.h> -#include <linux/mutex.h> - -#include "planb.h" -#include "saa7196.h" - -/* Would you mind for some ugly debugging? */ -#if 0 /* keep */; -#define DEBUG(x...) printk(KERN_DEBUG ## x) /* Debug driver */ -#else -#define DEBUG(x...) /* Don't debug driver */ -#endif - -#if 0 /* keep */; -#define IDEBUG(x...) printk(KERN_DEBUG ## x) /* Debug interrupt part */ -#else -#define IDEBUG(x...) /* Don't debug interrupt part */ -#endif - -/* Ever seen a Mac with more than 1 of these? */ -#define PLANB_MAX 1 - -static int planb_num; -static struct planb planbs[PLANB_MAX]; -static volatile struct planb_registers *planb_regs; - -static int def_norm = PLANB_DEF_NORM; /* default norm */ -static int video_nr = -1; - -module_param(def_norm, int, 0); -MODULE_PARM_DESC(def_norm, "Default startup norm (0=PAL, 1=NTSC, 2=SECAM)"); -module_param(video_nr, int, 0); -MODULE_LICENSE("GPL"); - - -/* ------------------ PlanB Exported Functions ------------------ */ -static long planb_write(struct video_device *, const char *, unsigned long, int); -static long planb_read(struct video_device *, char *, unsigned long, int); -static int planb_open(struct video_device *, int); -static void planb_close(struct video_device *); -static int planb_ioctl(struct video_device *, unsigned int, void *); -static int planb_init_done(struct video_device *); -static int planb_mmap(struct video_device *, const char *, unsigned long); -static void release_planb(void); -int init_planbs(struct video_init *); - -/* ------------------ PlanB Internal Functions ------------------ */ -static int planb_prepare_open(struct planb *); -static void planb_prepare_close(struct planb *); -static void saa_write_reg(unsigned char, unsigned char); -static unsigned char saa_status(int, struct planb *); -static void saa_set(unsigned char, unsigned char, struct planb *); -static void saa_init_regs(struct planb *); -static int grabbuf_alloc(struct planb *); -static int vgrab(struct planb *, struct video_mmap *); -static void add_clip(struct planb *, struct video_clip *); -static void fill_cmd_buff(struct planb *); -static void cmd_buff(struct planb *); -static volatile struct dbdma_cmd *setup_grab_cmd(int, struct planb *); -static void overlay_start(struct planb *); -static void overlay_stop(struct planb *); -static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *, unsigned short, - unsigned int); -static inline void tab_cmd_store(volatile struct dbdma_cmd *, unsigned int, - unsigned int); -static inline void tab_cmd_gen(volatile struct dbdma_cmd *, unsigned short, - unsigned short, unsigned int, unsigned int); -static int init_planb(struct planb *); -static int find_planb(void); -static void planb_pre_capture(int, int, struct planb *); -static volatile struct dbdma_cmd *cmd_geo_setup(volatile struct dbdma_cmd *, - int, int, int, int, int, struct planb *); -static inline void planb_dbdma_stop(volatile struct dbdma_regs *); -static unsigned int saa_geo_setup(int, int, int, int, struct planb *); -static inline int overlay_is_active(struct planb *); - -/*******************************/ -/* Memory management functions */ -/*******************************/ - -static int grabbuf_alloc(struct planb *pb) -{ - int i, npage; - - npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1) -#ifndef PLANB_GSCANLINE - + MAX_LNUM -#endif /* PLANB_GSCANLINE */ - ); - if ((pb->rawbuf = kmalloc(npage - * sizeof(unsigned long), GFP_KERNEL)) == 0) - return -ENOMEM; - for (i = 0; i < npage; i++) { - pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL - |GFP_DMA, 0); - if (!pb->rawbuf[i]) - break; - SetPageReserved(virt_to_page(pb->rawbuf[i])); - } - if (i-- < npage) { - printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n"); - for (; i > 0; i--) { - ClearPageReserved(virt_to_page(pb->rawbuf[i])); - free_pages((unsigned long)pb->rawbuf[i], 0); - } - kfree(pb->rawbuf); - return -ENOBUFS; - } - pb->rawbuf_size = npage; - return 0; -} - -/*****************************/ -/* Hardware access functions */ -/*****************************/ - -static void saa_write_reg(unsigned char addr, unsigned char val) -{ - planb_regs->saa_addr = addr; eieio(); - planb_regs->saa_regval = val; eieio(); - return; -} - -/* return status byte 0 or 1: */ -static unsigned char saa_status(int byte, struct planb *pb) -{ - saa_regs[pb->win.norm][SAA7196_STDC] = - (saa_regs[pb->win.norm][SAA7196_STDC] & ~2) | ((byte & 1) << 1); - saa_write_reg (SAA7196_STDC, saa_regs[pb->win.norm][SAA7196_STDC]); - - /* Let's wait 30msec for this one */ - msleep_interruptible(30); - - return (unsigned char)in_8 (&planb_regs->saa_status); -} - -static void saa_set(unsigned char addr, unsigned char val, struct planb *pb) -{ - if(saa_regs[pb->win.norm][addr] != val) { - saa_regs[pb->win.norm][addr] = val; - saa_write_reg (addr, val); - } - return; -} - -static void saa_init_regs(struct planb *pb) -{ - int i; - - for (i = 0; i < SAA7196_NUMREGS; i++) - saa_write_reg (i, saa_regs[pb->win.norm][i]); -} - -static unsigned int saa_geo_setup(int width, int height, int interlace, int bpp, - struct planb *pb) -{ - int ht, norm = pb->win.norm; - - switch(bpp) { - case 2: - /* RGB555+a 1x16-bit + 16-bit transparent */ - saa_regs[norm][SAA7196_FMTS] &= ~0x3; - break; - case 1: - case 4: - /* RGB888 1x24-bit + 8-bit transparent */ - saa_regs[norm][SAA7196_FMTS] &= ~0x1; - saa_regs[norm][SAA7196_FMTS] |= 0x2; - break; - default: - return -EINVAL; - } - ht = (interlace ? height / 2 : height); - saa_regs[norm][SAA7196_OUTPIX] = (unsigned char) (width & 0x00ff); - saa_regs[norm][SAA7196_HFILT] = (saa_regs[norm][SAA7196_HFILT] & ~0x3) - | (width >> 8 & 0x3); - saa_regs[norm][SAA7196_OUTLINE] = (unsigned char) (ht & 0xff); - saa_regs[norm][SAA7196_VYP] = (saa_regs[norm][SAA7196_VYP] & ~0x3) - | (ht >> 8 & 0x3); - /* feed both fields if interlaced, or else feed only even fields */ - saa_regs[norm][SAA7196_FMTS] = (interlace) ? - (saa_regs[norm][SAA7196_FMTS] & ~0x60) - : (saa_regs[norm][SAA7196_FMTS] | 0x60); - /* transparent mode; extended format enabled */ - saa_regs[norm][SAA7196_DPATH] |= 0x3; - - return 0; -} - -/***************************/ -/* DBDMA support functions */ -/***************************/ - -static inline void planb_dbdma_restart(volatile struct dbdma_regs *ch) -{ - out_le32(&ch->control, PLANB_CLR(RUN)); - out_le32(&ch->control, PLANB_SET(RUN|WAKE) | PLANB_CLR(PAUSE)); -} - -static inline void planb_dbdma_stop(volatile struct dbdma_regs *ch) -{ - int i = 0; - - out_le32(&ch->control, PLANB_CLR(RUN) | PLANB_SET(FLUSH)); - while((in_le32(&ch->status) == (ACTIVE | FLUSH)) && (i < 999)) { - IDEBUG("PlanB: waiting for DMA to stop\n"); - i++; - } -} - -static inline void tab_cmd_dbdma(volatile struct dbdma_cmd *ch, - unsigned short command, unsigned int cmd_dep) -{ - st_le16(&ch->command, command); - st_le32(&ch->cmd_dep, cmd_dep); -} - -static inline void tab_cmd_store(volatile struct dbdma_cmd *ch, - unsigned int phy_addr, unsigned int cmd_dep) -{ - st_le16(&ch->command, STORE_WORD | KEY_SYSTEM); - st_le16(&ch->req_count, 4); - st_le32(&ch->phy_addr, phy_addr); - st_le32(&ch->cmd_dep, cmd_dep); -} - -static inline void tab_cmd_gen(volatile struct dbdma_cmd *ch, - unsigned short command, unsigned short req_count, - unsigned int phy_addr, unsigned int cmd_dep) -{ - st_le16(&ch->command, command); - st_le16(&ch->req_count, req_count); - st_le32(&ch->phy_addr, phy_addr); - st_le32(&ch->cmd_dep, cmd_dep); -} - -static volatile struct dbdma_cmd *cmd_geo_setup( - volatile struct dbdma_cmd *c1, int width, int height, int interlace, - int bpp, int clip, struct planb *pb) -{ - int norm = pb->win.norm; - - if((saa_geo_setup(width, height, interlace, bpp, pb)) != 0) - return (volatile struct dbdma_cmd *)NULL; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_FMTS); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_FMTS]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_DPATH); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_DPATH]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->even), - bpp | ((clip)? PLANB_CLIPMASK: 0)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->odd), - bpp | ((clip)? PLANB_CLIPMASK: 0)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_OUTPIX); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_OUTPIX]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_HFILT); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_HFILT]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_OUTLINE); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_OUTLINE]); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_addr), - SAA7196_VYP); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->saa_regval), - saa_regs[norm][SAA7196_VYP]); - return c1; -} - -/******************************/ -/* misc. supporting functions */ -/******************************/ - -static inline void planb_lock(struct planb *pb) -{ - mutex_lock(&pb->lock); -} - -static inline void planb_unlock(struct planb *pb) -{ - mutex_unlock(&pb->lock); -} - -/***************/ -/* Driver Core */ -/***************/ - -static int planb_prepare_open(struct planb *pb) -{ - int i, size; - - /* allocate memory for two plus alpha command buffers (size: max lines, - plus 40 commands handling, plus 1 alignment), plus dummy command buf, - plus clipmask buffer, plus frame grabbing status */ - size = (pb->tab_size*(2+MAX_GBUFFERS*TAB_FACTOR)+1+MAX_GBUFFERS - * PLANB_DUMMY)*sizeof(struct dbdma_cmd) - +(PLANB_MAXLINES*((PLANB_MAXPIXELS+7)& ~7))/8 - +MAX_GBUFFERS*sizeof(unsigned int); - if ((pb->priv_space = kzalloc (size, GFP_KERNEL)) == 0) - return -ENOMEM; - pb->overlay_last1 = pb->ch1_cmd = (volatile struct dbdma_cmd *) - DBDMA_ALIGN (pb->priv_space); - pb->overlay_last2 = pb->ch2_cmd = pb->ch1_cmd + pb->tab_size; - pb->ch1_cmd_phys = virt_to_bus(pb->ch1_cmd); - pb->cap_cmd[0] = pb->ch2_cmd + pb->tab_size; - pb->pre_cmd[0] = pb->cap_cmd[0] + pb->tab_size * TAB_FACTOR; - for (i = 1; i < MAX_GBUFFERS; i++) { - pb->cap_cmd[i] = pb->pre_cmd[i-1] + PLANB_DUMMY; - pb->pre_cmd[i] = pb->cap_cmd[i] + pb->tab_size * TAB_FACTOR; - } - pb->frame_stat=(volatile unsigned int *)(pb->pre_cmd[MAX_GBUFFERS-1] - + PLANB_DUMMY); - pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS); - - pb->rawbuf = NULL; - pb->rawbuf_size = 0; - pb->grabbing = 0; - for (i = 0; i < MAX_GBUFFERS; i++) { - pb->frame_stat[i] = GBUFFER_UNUSED; - pb->gwidth[i] = 0; - pb->gheight[i] = 0; - pb->gfmt[i] = 0; - pb->gnorm_switch[i] = 0; -#ifndef PLANB_GSCANLINE - pb->lsize[i] = 0; - pb->lnum[i] = 0; -#endif /* PLANB_GSCANLINE */ - } - pb->gcount = 0; - pb->suspend = 0; - pb->last_fr = -999; - pb->prev_last_fr = -999; - - /* Reset DMA controllers */ - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - - return 0; -} - -static void planb_prepare_close(struct planb *pb) -{ - int i; - - /* make sure the dma's are idle */ - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - /* free kernel memory of command buffers */ - if(pb->priv_space != 0) { - kfree (pb->priv_space); - pb->priv_space = 0; - pb->cmd_buff_inited = 0; - } - if(pb->rawbuf) { - for (i = 0; i < pb->rawbuf_size; i++) { - ClearPageReserved(virt_to_page(pb->rawbuf[i])); - free_pages((unsigned long)pb->rawbuf[i], 0); - } - kfree(pb->rawbuf); - } - pb->rawbuf = NULL; -} - -/*****************************/ -/* overlay support functions */ -/*****************************/ - -static inline int overlay_is_active(struct planb *pb) -{ - unsigned int size = pb->tab_size * sizeof(struct dbdma_cmd); - unsigned int caddr = (unsigned)in_le32(&pb->planb_base->ch1.cmdptr); - - return (in_le32(&pb->overlay_last1->cmd_dep) == pb->ch1_cmd_phys) - && (caddr < (pb->ch1_cmd_phys + size)) - && (caddr >= (unsigned)pb->ch1_cmd_phys); -} - -static void overlay_start(struct planb *pb) -{ - - DEBUG("PlanB: overlay_start()\n"); - - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { - - DEBUG("PlanB: presumably, grabbing is in progress...\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - out_le32 (&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->ch2_cmd)); - planb_dbdma_restart(&pb->planb_base->ch2); - st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); - eieio(); - pb->prev_last_fr = pb->last_fr; - pb->last_fr = -2; - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { - IDEBUG("PlanB: became inactive " - "in the mean time... reactivating\n"); - planb_dbdma_stop(&pb->planb_base->ch1); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->ch1_cmd)); - planb_dbdma_restart(&pb->planb_base->ch1); - } - } else { - - DEBUG("PlanB: currently idle, so can do whatever\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - st_le32 (&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->ch2_cmd)); - st_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->ch1_cmd)); - out_le16 (&pb->ch1_cmd->command, DBDMA_NOP); - planb_dbdma_restart(&pb->planb_base->ch2); - planb_dbdma_restart(&pb->planb_base->ch1); - pb->last_fr = -1; - } - return; -} - -static void overlay_stop(struct planb *pb) -{ - DEBUG("PlanB: overlay_stop()\n"); - - if(pb->last_fr == -1) { - - DEBUG("PlanB: no grabbing, it seems...\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - pb->last_fr = -999; - } else if(pb->last_fr == -2) { - unsigned int cmd_dep; - tab_cmd_dbdma(pb->cap_cmd[pb->prev_last_fr], DBDMA_STOP, 0); - eieio(); - cmd_dep = (unsigned int)in_le32(&pb->overlay_last1->cmd_dep); - if(overlay_is_active(pb)) { - - DEBUG("PlanB: overlay is currently active\n"); - - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - if(cmd_dep != pb->ch1_cmd_phys) { - out_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->overlay_last1)); - planb_dbdma_restart(&pb->planb_base->ch1); - } - } - pb->last_fr = pb->prev_last_fr; - pb->prev_last_fr = -999; - } - return; -} - -static void suspend_overlay(struct planb *pb) -{ - int fr = -1; - struct dbdma_cmd last; - - DEBUG("PlanB: suspend_overlay: %d\n", pb->suspend); - - if(pb->suspend++) - return; - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { - if(pb->last_fr == -2) { - fr = pb->prev_last_fr; - memcpy(&last, (void*)pb->last_cmd[fr], sizeof(last)); - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); - } - if(overlay_is_active(pb)) { - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - pb->suspended.overlay = 1; - pb->suspended.frame = fr; - memcpy(&pb->suspended.cmd, &last, sizeof(last)); - return; - } - } - pb->suspended.overlay = 0; - pb->suspended.frame = fr; - memcpy(&pb->suspended.cmd, &last, sizeof(last)); - return; -} - -static void resume_overlay(struct planb *pb) -{ - - DEBUG("PlanB: resume_overlay: %d\n", pb->suspend); - - if(pb->suspend > 1) - return; - if(pb->suspended.frame != -1) { - memcpy((void*)pb->last_cmd[pb->suspended.frame], - &pb->suspended.cmd, sizeof(pb->suspended.cmd)); - } - if(ACTIVE & in_le32(&pb->planb_base->ch1.status)) { - goto finish; - } - if(pb->suspended.overlay) { - - DEBUG("PlanB: overlay being resumed\n"); - - st_le16 (&pb->ch1_cmd->command, DBDMA_NOP); - st_le16 (&pb->ch2_cmd->command, DBDMA_NOP); - /* Set command buffer addresses */ - st_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->overlay_last1)); - out_le32(&pb->planb_base->ch2.cmdptr, - virt_to_bus(pb->overlay_last2)); - /* Start the DMA controller */ - out_le32 (&pb->planb_base->ch2.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); - out_le32 (&pb->planb_base->ch1.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); - } else if(pb->suspended.frame != -1) { - out_le32(&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->last_cmd[pb->suspended.frame])); - out_le32 (&pb->planb_base->ch1.control, - PLANB_CLR(PAUSE) | PLANB_SET(RUN|WAKE)); - } - -finish: - pb->suspend--; - wake_up_interruptible(&pb->suspendq); -} - -static void add_clip(struct planb *pb, struct video_clip *clip) -{ - volatile unsigned char *base; - int xc = clip->x, yc = clip->y; - int wc = clip->width, hc = clip->height; - int ww = pb->win.width, hw = pb->win.height; - int x, y, xtmp1, xtmp2; - - DEBUG("PlanB: clip %dx%d+%d+%d\n", wc, hc, xc, yc); - - if(xc < 0) { - wc += xc; - xc = 0; - } - if(yc < 0) { - hc += yc; - yc = 0; - } - if(xc + wc > ww) - wc = ww - xc; - if(wc <= 0) /* Nothing to do */ - return; - if(yc + hc > hw) - hc = hw - yc; - - for (y = yc; y < yc+hc; y++) { - xtmp1=xc>>3; - xtmp2=(xc+wc)>>3; - base = pb->mask + y*96; - if(xc != 0 || wc >= 8) - *(base + xtmp1) &= (unsigned char)(0x00ff & - (0xff00 >> (xc&7))); - for (x = xtmp1 + 1; x < xtmp2; x++) { - *(base + x) = 0; - } - if(xc < (ww & ~0x7)) - *(base + xtmp2) &= (unsigned char)(0x00ff >> - ((xc+wc) & 7)); - } - - return; -} - -static void fill_cmd_buff(struct planb *pb) -{ - int restore = 0; - volatile struct dbdma_cmd last; - - DEBUG("PlanB: fill_cmd_buff()\n"); - - if(pb->overlay_last1 != pb->ch1_cmd) { - restore = 1; - last = *(pb->overlay_last1); - } - memset ((void *) pb->ch1_cmd, 0, 2 * pb->tab_size - * sizeof(struct dbdma_cmd)); - cmd_buff (pb); - if(restore) - *(pb->overlay_last1) = last; - if(pb->suspended.overlay) { - unsigned long jump_addr = in_le32(&pb->overlay_last1->cmd_dep); - if(jump_addr != pb->ch1_cmd_phys) { - int i; - - DEBUG("PlanB: adjusting ch1's jump address\n"); - - for(i = 0; i < MAX_GBUFFERS; i++) { - if(pb->need_pre_capture[i]) { - if(jump_addr == virt_to_bus(pb->pre_cmd[i])) - goto found; - } else { - if(jump_addr == virt_to_bus(pb->cap_cmd[i])) - goto found; - } - } - - DEBUG("PlanB: not found...\n"); - - goto out; -found: - if(pb->need_pre_capture[i]) - out_le32(&pb->pre_cmd[i]->phy_addr, - virt_to_bus(pb->overlay_last1)); - else - out_le32(&pb->cap_cmd[i]->phy_addr, - virt_to_bus(pb->overlay_last1)); - } - } -out: - pb->cmd_buff_inited = 1; - - return; -} - -static void cmd_buff(struct planb *pb) -{ - int i, bpp, count, nlines, stepsize, interlace; - unsigned long base, jump, addr_com, addr_dep; - volatile struct dbdma_cmd *c1 = pb->ch1_cmd; - volatile struct dbdma_cmd *c2 = pb->ch2_cmd; - - interlace = pb->win.interlace; - bpp = pb->win.bpp; - count = (bpp * ((pb->win.x + pb->win.width > pb->win.swidth) ? - (pb->win.swidth - pb->win.x) : pb->win.width)); - nlines = ((pb->win.y + pb->win.height > pb->win.sheight) ? - (pb->win.sheight - pb->win.y) : pb->win.height); - - /* Do video in: */ - - /* Preamble commands: */ - addr_com = virt_to_bus(c1); - addr_dep = virt_to_bus(&c1->cmd_dep); - tab_cmd_dbdma(c1++, DBDMA_NOP, 0); - jump = virt_to_bus(c1+16); /* 14 by cmd_geo_setup() and 2 for padding */ - if((c1 = cmd_geo_setup(c1, pb->win.width, pb->win.height, interlace, - bpp, 1, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered serious problems\n"); - tab_cmd_dbdma(pb->ch1_cmd + 1, DBDMA_STOP, 0); - tab_cmd_dbdma(pb->ch2_cmd + 1, DBDMA_STOP, 0); - return; - } - tab_cmd_store(c1++, addr_com, (unsigned)(DBDMA_NOP | BR_ALWAYS) << 16); - tab_cmd_store(c1++, addr_dep, jump); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), - PLANB_SET(FIELD_SYNC)); - /* (1) wait for field sync to be set */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - /* wait for field sync to be cleared */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - /* if not odd field, wait until field sync is set again */ - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; - /* assert ch_sync to ch2 */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), - PLANB_SET(CH_SYNC)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - base = (pb->frame_buffer_phys + pb->offset + pb->win.y * (pb->win.bpl - + pb->win.pad) + pb->win.x * bpp); - - if (interlace) { - stepsize = 2; - jump = virt_to_bus(c1 + (nlines + 1) / 2); - } else { - stepsize = 1; - jump = virt_to_bus(c1 + nlines); - } - - /* even field data: */ - for (i=0; i < nlines; i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, - count, base + i * (pb->win.bpl + pb->win.pad), jump); - - /* For non-interlaced, we use even fields only */ - if (!interlace) - goto cmd_tab_data_end; - - /* Resync to odd field */ - /* (2) wait for field sync to be set */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - /* wait for field sync to be cleared */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - /* if not odd field, wait until field sync is set again */ - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; - /* assert ch_sync to ch2 */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch2.control), - PLANB_SET(CH_SYNC)); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - /* odd field data: */ - jump = virt_to_bus(c1 + nlines / 2); - for (i=1; i < nlines; i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, - base + i * (pb->win.bpl + pb->win.pad), jump); - - /* And jump back to the start */ -cmd_tab_data_end: - pb->overlay_last1 = c1; /* keep a pointer to the last command */ - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch1_cmd)); - - /* Clipmask command buffer */ - - /* Preamble commands: */ - tab_cmd_dbdma(c2++, DBDMA_NOP, 0); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), - PLANB_SET(CH_SYNC)); - /* wait until ch1 asserts ch_sync */ - tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); - /* clear ch_sync asserted by ch1 */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.control), - PLANB_CLR(CH_SYNC)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.wait_sel), - PLANB_SET(FIELD_SYNC)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), - PLANB_SET(ODD_FIELD)); - - /* jump to end of even field if appropriate */ - /* this points to (interlace)? pos. C: pos. B */ - jump = (interlace) ? virt_to_bus(c2 + (nlines + 1) / 2 + 2): - virt_to_bus(c2 + nlines + 2); - /* if odd field, skip over to odd field clipmasking */ - tab_cmd_dbdma(c2++, DBDMA_NOP | BR_IFSET, jump); - - /* even field mask: */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), - PLANB_SET(DMA_ABORT)); - /* this points to pos. B */ - jump = (interlace) ? virt_to_bus(c2 + nlines + 1): - virt_to_bus(c2 + nlines); - base = virt_to_bus(pb->mask); - for (i=0; i < nlines; i += stepsize, c2++) - tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, - base + i * 96, jump); - - /* For non-interlaced, we use only even fields */ - if(!interlace) - goto cmd_tab_mask_end; - - /* odd field mask: */ -/* C */ tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch2.br_sel), - PLANB_SET(DMA_ABORT)); - /* this points to pos. B */ - jump = virt_to_bus(c2 + nlines / 2); - base = virt_to_bus(pb->mask); - for (i=1; i < nlines; i += 2, c2++) /* abort if set */ - tab_cmd_gen(c2, OUTPUT_MORE | KEY_STREAM0 | BR_IFSET, 96, - base + i * 96, jump); - - /* Inform channel 1 and jump back to start */ -cmd_tab_mask_end: - /* ok, I just realized this is kind of flawed. */ - /* this part is reached only after odd field clipmasking. */ - /* wanna clean up? */ - /* wait for field sync to be set */ - /* corresponds to fsync (1) of ch1 */ -/* B */ tab_cmd_dbdma(c2++, DBDMA_NOP | WAIT_IFCLR, 0); - /* restart ch1, meant to clear any dead bit or something */ - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), - PLANB_CLR(RUN)); - tab_cmd_store(c2++, (unsigned)(&pb->planb_base_phys->ch1.control), - PLANB_SET(RUN)); - pb->overlay_last2 = c2; /* keep a pointer to the last command */ - /* start over even field clipmasking */ - tab_cmd_dbdma(c2, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->ch2_cmd)); - - eieio(); - return; -} - -/*********************************/ -/* grabdisplay support functions */ -/*********************************/ - -static int palette2fmt[] = { - 0, - PLANB_GRAY, - 0, - 0, - 0, - PLANB_COLOUR32, - PLANB_COLOUR15, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, -}; - -#define PLANB_PALETTE_MAX 15 - -static int vgrab(struct planb *pb, struct video_mmap *mp) -{ - unsigned int fr = mp->frame; - unsigned int format; - - if(pb->rawbuf==NULL) { - int err; - if((err=grabbuf_alloc(pb))) - return err; - } - - IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing, - mp->width, mp->height, fr); - - if(pb->grabbing >= MAX_GBUFFERS) - return -ENOBUFS; - if(fr > (MAX_GBUFFERS - 1) || fr < 0) - return -EINVAL; - if(mp->height <= 0 || mp->width <= 0) - return -EINVAL; - if(mp->format < 0 || mp->format >= PLANB_PALETTE_MAX) - return -EINVAL; - if((format = palette2fmt[mp->format]) == 0) - return -EINVAL; - if (mp->height * mp->width * format > PLANB_MAX_FBUF) /* format = bpp */ - return -EINVAL; - - planb_lock(pb); - if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] || - format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) { - int i; -#ifndef PLANB_GSCANLINE - unsigned int osize = pb->gwidth[fr] * pb->gheight[fr] - * pb->gfmt[fr]; - unsigned int nsize = mp->width * mp->height * format; -#endif - - IDEBUG("PlanB: gwidth = %d, gheight = %d, mp->format = %u\n", - mp->width, mp->height, mp->format); - -#ifndef PLANB_GSCANLINE - if(pb->gnorm_switch[fr]) - nsize = 0; - if (nsize < osize) { - for(i = pb->gbuf_idx[fr]; osize > 0; i++) { - memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); - osize -= PAGE_SIZE; - } - } - for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr] - + pb->lnum[fr]; i++) - memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); -#else -/* XXX TODO */ -/* - if(pb->gnorm_switch[fr]) - memset((void *)pb->gbuffer[fr], 0, - pb->gbytes_per_line * pb->gheight[fr]); - else { - if(mp-> - for(i = 0; i < pb->gheight[fr]; i++) { - memset((void *)(pb->gbuffer[fr] - + pb->gbytes_per_line * i - } - } -*/ -#endif - pb->gwidth[fr] = mp->width; - pb->gheight[fr] = mp->height; - pb->gfmt[fr] = format; - pb->last_cmd[fr] = setup_grab_cmd(fr, pb); - planb_pre_capture(fr, pb->gfmt[fr], pb); /* gfmt = bpp */ - pb->need_pre_capture[fr] = 1; - pb->gnorm_switch[fr] = 0; - } else - pb->need_pre_capture[fr] = 0; - pb->frame_stat[fr] = GBUFFER_GRABBING; - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { - - IDEBUG("PlanB: ch1 inactive, initiating grabbing\n"); - - planb_dbdma_stop(&pb->planb_base->ch1); - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->pre_cmd[fr])); - } else { - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); - /* let's be on the safe side. here is not timing critical. */ - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), DBDMA_NOP, 0); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->cap_cmd[fr])); - } - planb_dbdma_restart(&pb->planb_base->ch1); - pb->last_fr = fr; - } else { - int i; - - IDEBUG("PlanB: ch1 active, grabbing being queued\n"); - - if((pb->last_fr == -1) || ((pb->last_fr == -2) && - overlay_is_active(pb))) { - - IDEBUG("PlanB: overlay is active, grabbing defered\n"); - - tab_cmd_dbdma(pb->last_cmd[fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - tab_cmd_store(pb->pre_cmd[fr], - virt_to_bus(&pb->overlay_last1->cmd_dep), - virt_to_bus(pb->ch1_cmd)); - eieio(); - out_le32 (&pb->overlay_last1->cmd_dep, - virt_to_bus(pb->pre_cmd[fr])); - } else { - tab_cmd_store(pb->cap_cmd[fr], - virt_to_bus(&pb->overlay_last1->cmd_dep), - virt_to_bus(pb->ch1_cmd)); - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP, 0); - eieio(); - out_le32 (&pb->overlay_last1->cmd_dep, - virt_to_bus(pb->cap_cmd[fr])); - } - for(i = 0; overlay_is_active(pb) && i < 999; i++) - IDEBUG("PlanB: waiting for overlay done\n"); - tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); - pb->prev_last_fr = fr; - pb->last_fr = -2; - } else if(pb->last_fr == -2) { - - IDEBUG("PlanB: mixed mode detected, grabbing" - " will be done before activating overlay\n"); - - tab_cmd_dbdma(pb->ch1_cmd, DBDMA_NOP, 0); - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->pre_cmd[fr])); - eieio(); - } else { - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); - if(pb->gwidth[pb->prev_last_fr] != - pb->gwidth[fr] - || pb->gheight[pb->prev_last_fr] != - pb->gheight[fr] - || pb->gfmt[pb->prev_last_fr] != - pb->gfmt[fr]) - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP, 0); - else - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr] + 16)); - tab_cmd_dbdma(pb->last_cmd[pb->prev_last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr])); - eieio(); - } - tab_cmd_dbdma(pb->last_cmd[fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->ch1_cmd)); - eieio(); - pb->prev_last_fr = fr; - pb->last_fr = -2; - } else { - - IDEBUG("PlanB: active grabbing session detected\n"); - - if(pb->need_pre_capture[fr]) { - - IDEBUG("PlanB: padding pre-capture sequence\n"); - - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->pre_cmd[fr])); - eieio(); - } else { - tab_cmd_dbdma(pb->last_cmd[fr], DBDMA_STOP, 0); - tab_cmd_dbdma(pb->cap_cmd[fr], DBDMA_NOP, 0); - if(pb->gwidth[pb->last_fr] != pb->gwidth[fr] - || pb->gheight[pb->last_fr] != - pb->gheight[fr] - || pb->gfmt[pb->last_fr] != - pb->gfmt[fr]) - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP, 0); - else - tab_cmd_dbdma((pb->cap_cmd[fr] + 1), - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr] + 16)); - tab_cmd_dbdma(pb->last_cmd[pb->last_fr], - DBDMA_NOP | BR_ALWAYS, - virt_to_bus(pb->cap_cmd[fr])); - eieio(); - } - pb->last_fr = fr; - } - if(!(ACTIVE & in_le32(&pb->planb_base->ch1.status))) { - - IDEBUG("PlanB: became inactive in the mean time..." - "reactivating\n"); - - planb_dbdma_stop(&pb->planb_base->ch1); - out_le32 (&pb->planb_base->ch1.cmdptr, - virt_to_bus(pb->cap_cmd[fr])); - planb_dbdma_restart(&pb->planb_base->ch1); - } - } - pb->grabbing++; - planb_unlock(pb); - - return 0; -} - -static void planb_pre_capture(int fr, int bpp, struct planb *pb) -{ - volatile struct dbdma_cmd *c1 = pb->pre_cmd[fr]; - int interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; - - tab_cmd_dbdma(c1++, DBDMA_NOP, 0); - if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, - bpp, 0, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered some problems\n"); - tab_cmd_dbdma(pb->pre_cmd[fr] + 1, DBDMA_STOP, 0); - return; - } - /* Sync to even field */ - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), - PLANB_SET(FIELD_SYNC)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; - tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - /* For non-interlaced, we use even fields only */ - if (pb->gheight[fr] <= pb->maxlines/2) - goto cmd_tab_data_end; - /* Sync to odd field */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); -cmd_tab_data_end: - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(pb->cap_cmd[fr])); - - eieio(); -} - -static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) -{ - int i, bpp, count, nlines, stepsize, interlace; -#ifdef PLANB_GSCANLINE - int scanline; -#else - int nlpp, leftover1; - unsigned long base; -#endif - unsigned long jump; - int pagei; - volatile struct dbdma_cmd *c1; - volatile struct dbdma_cmd *jump_addr; - - c1 = pb->cap_cmd[fr]; - interlace = (pb->gheight[fr] > pb->maxlines/2)? 1: 0; - bpp = pb->gfmt[fr]; /* gfmt = bpp */ - count = bpp * pb->gwidth[fr]; - nlines = pb->gheight[fr]; -#ifdef PLANB_GSCANLINE - scanline = pb->gbytes_per_line; -#else - pb->lsize[fr] = count; - pb->lnum[fr] = 0; -#endif - - /* Do video in: */ - - /* Preamble commands: */ - tab_cmd_dbdma(c1++, DBDMA_NOP, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, virt_to_bus(c1 + 16)); c1++; - if((c1 = cmd_geo_setup(c1, pb->gwidth[fr], pb->gheight[fr], interlace, - bpp, 0, pb)) == NULL) { - printk(KERN_WARNING "PlanB: encountered serious problems\n"); - tab_cmd_dbdma(pb->cap_cmd[fr] + 1, DBDMA_STOP, 0); - return (pb->cap_cmd[fr] + 2); - } - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.wait_sel), - PLANB_SET(FIELD_SYNC)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFSET, virt_to_bus(c1-3)); c1++; - tab_cmd_dbdma(c1++, DBDMA_NOP | INTR_ALWAYS, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - if (interlace) { - stepsize = 2; - jump_addr = c1 + TAB_FACTOR * (nlines + 1) / 2; - } else { - stepsize = 1; - jump_addr = c1 + TAB_FACTOR * nlines; - } - jump = virt_to_bus(jump_addr); - - /* even field data: */ - - pagei = pb->gbuf_idx[fr]; -#ifdef PLANB_GSCANLINE - for (i = 0; i < nlines; i += stepsize) { - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pagei - + i * scanline / PAGE_SIZE]), jump); - } -#else - i = 0; - leftover1 = 0; - do { - int j; - - base = virt_to_bus(pb->rawbuf[pagei]); - nlpp = (PAGE_SIZE - leftover1) / count / stepsize; - for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, - count, base + count * j * stepsize + leftover1, jump); - if(i < nlines) { - int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; - - if(lov0 == 0) - leftover1 = 0; - else { - if(lov0 >= count) { - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base - + count * nlpp * stepsize + leftover1, jump); - } else { - pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] - + count * nlpp * stepsize + leftover1; - pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; - pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0; - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] - + pb->lnum[fr]]), jump); - if(++pb->lnum[fr] > MAX_LNUM) - pb->lnum[fr]--; - } - leftover1 = count * stepsize - lov0; - i += stepsize; - } - } - pagei++; - } while(i < nlines); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); - c1 = jump_addr; -#endif /* PLANB_GSCANLINE */ - - /* For non-interlaced, we use even fields only */ - if (!interlace) - goto cmd_tab_data_end; - - /* Sync to odd field */ - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFCLR, 0); - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(ODD_FIELD)); - tab_cmd_dbdma(c1++, DBDMA_NOP | WAIT_IFSET, 0); - tab_cmd_dbdma(c1, DBDMA_NOP | BR_IFCLR, virt_to_bus(c1-3)); c1++; - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->ch1.br_sel), - PLANB_SET(DMA_ABORT)); - - /* odd field data: */ - jump_addr = c1 + TAB_FACTOR * nlines / 2; - jump = virt_to_bus(jump_addr); -#ifdef PLANB_GSCANLINE - for (i = 1; i < nlines; i += stepsize) { - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pagei - + i * scanline / PAGE_SIZE]), jump); - } -#else - i = 1; - leftover1 = 0; - pagei = pb->gbuf_idx[fr]; - if(nlines <= 1) - goto skip; - do { - int j; - - base = virt_to_bus(pb->rawbuf[pagei]); - nlpp = (PAGE_SIZE - leftover1) / count / stepsize; - if(leftover1 >= count) { - tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, - base + leftover1 - count, jump); - i += stepsize; - } - for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) - tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, - base + count * (j * stepsize + 1) + leftover1, jump); - if(i < nlines) { - int lov0 = PAGE_SIZE - count * nlpp * stepsize - leftover1; - - if(lov0 == 0) - leftover1 = 0; - else { - if(lov0 > count) { - pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] - + count * (nlpp * stepsize + 1) + leftover1; - pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; - pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize - - lov0; - tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] - + pb->lnum[fr]]), jump); - if(++pb->lnum[fr] > MAX_LNUM) - pb->lnum[fr]--; - i += stepsize; - } - leftover1 = count * stepsize - lov0; - } - } - pagei++; - } while(i < nlines); -skip: - tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); - c1 = jump_addr; -#endif /* PLANB_GSCANLINE */ - -cmd_tab_data_end: - tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat), - (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ); - /* stop it */ - tab_cmd_dbdma(c1, DBDMA_STOP, 0); - - eieio(); - return c1; -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19) -static irqreturn_t planb_irq(int irq, void *dev_id, struct pt_regs * regs) -#else -static irqreturn_t planb_irq(int irq, void *dev_id) -#endif -{ - unsigned int stat, astat; - struct planb *pb = (struct planb *)dev_id; - - IDEBUG("PlanB: planb_irq()\n"); - - /* get/clear interrupt status bits */ - eieio(); - stat = in_le32(&pb->planb_base->intr_stat); - astat = stat & pb->intr_mask; - out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ - & ~astat & stat & ~PLANB_GEN_IRQ); - IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat); - - if(astat & PLANB_FRM_IRQ) { - unsigned int fr = stat >> 9; -#ifndef PLANB_GSCANLINE - int i; -#endif - IDEBUG("PlanB: PLANB_FRM_IRQ\n"); - - pb->gcount++; - - IDEBUG("PlanB: grab %d: fr = %d, gcount = %d\n", - pb->grabbing, fr, pb->gcount); -#ifndef PLANB_GSCANLINE - IDEBUG("PlanB: %d * %d bytes are being copied over\n", - pb->lnum[fr], pb->lsize[fr]); - for(i = 0; i < pb->lnum[fr]; i++) { - int first = pb->lsize[fr] - pb->l_to_next_size[fr][i]; - - memcpy(pb->l_to_addr[fr][i], - pb->rawbuf[pb->l_fr_addr_idx[fr] + i], - first); - memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]], - pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first, - pb->l_to_next_size[fr][i]); - } -#endif - pb->frame_stat[fr] = GBUFFER_DONE; - pb->grabbing--; - wake_up_interruptible(&pb->capq); - return IRQ_HANDLED; - } - /* incorrect interrupts? */ - pb->intr_mask = PLANB_CLR_IRQ; - out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - printk(KERN_ERR "PlanB: IRQ lockup, cleared intrrupts" - " unconditionally\n"); - return IRQ_HANDLED; -} - -/******************************* - * Device Operations functions * - *******************************/ - -static int planb_open(struct video_device *dev, int mode) -{ - struct planb *pb = (struct planb *)dev; - - if (pb->user == 0) { - int err; - if((err = planb_prepare_open(pb)) != 0) - return err; - } - pb->user++; - - DEBUG("PlanB: device opened\n"); - return 0; -} - -static void planb_close(struct video_device *dev) -{ - struct planb *pb = (struct planb *)dev; - - if(pb->user < 1) /* ??? */ - return; - planb_lock(pb); - if (pb->user == 1) { - if (pb->overlay) { - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - pb->overlay = 0; - } - planb_prepare_close(pb); - } - pb->user--; - planb_unlock(pb); - - DEBUG("PlanB: device closed\n"); -} - -static long planb_read(struct video_device *v, char *buf, unsigned long count, - int nonblock) -{ - DEBUG("planb: read request\n"); - return -EINVAL; -} - -static long planb_write(struct video_device *v, const char *buf, - unsigned long count, int nonblock) -{ - DEBUG("planb: write request\n"); - return -EINVAL; -} - -static int planb_ioctl(struct video_device *dev, unsigned int cmd, void *arg) -{ - struct planb *pb=(struct planb *)dev; - - switch (cmd) - { - case VIDIOCGCAP: - { - struct video_capability b; - - DEBUG("PlanB: IOCTL VIDIOCGCAP\n"); - - strcpy (b.name, pb->video_dev.name); - b.type = VID_TYPE_OVERLAY | VID_TYPE_CLIPPING | - VID_TYPE_FRAMERAM | VID_TYPE_SCALES | - VID_TYPE_CAPTURE; - b.channels = 2; /* composite & svhs */ - b.audios = 0; - b.maxwidth = PLANB_MAXPIXELS; - b.maxheight = PLANB_MAXLINES; - b.minwidth = 32; /* wild guess */ - b.minheight = 32; - if (copy_to_user(arg,&b,sizeof(b))) - return -EFAULT; - return 0; - } - case VIDIOCSFBUF: - { - struct video_buffer v; - unsigned short bpp; - unsigned int fmt; - - DEBUG("PlanB: IOCTL VIDIOCSFBUF\n"); - - if (!capable(CAP_SYS_ADMIN) - || !capable(CAP_SYS_RAWIO)) - return -EPERM; - if (copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - planb_lock(pb); - switch(v.depth) { - case 8: - bpp = 1; - fmt = PLANB_GRAY; - break; - case 15: - case 16: - bpp = 2; - fmt = PLANB_COLOUR15; - break; - case 24: - case 32: - bpp = 4; - fmt = PLANB_COLOUR32; - break; - default: - planb_unlock(pb); - return -EINVAL; - } - if (bpp * v.width > v.bytesperline) { - planb_unlock(pb); - return -EINVAL; - } - pb->win.bpp = bpp; - pb->win.color_fmt = fmt; - pb->frame_buffer_phys = (unsigned long) v.base; - pb->win.sheight = v.height; - pb->win.swidth = v.width; - pb->picture.depth = pb->win.depth = v.depth; - pb->win.bpl = pb->win.bpp * pb->win.swidth; - pb->win.pad = v.bytesperline - pb->win.bpl; - - DEBUG("PlanB: Display at %p is %d by %d, bytedepth %d," - " bpl %d (+ %d)\n", v.base, v.width,v.height, - pb->win.bpp, pb->win.bpl, pb->win.pad); - - pb->cmd_buff_inited = 0; - if(pb->overlay) { - suspend_overlay(pb); - fill_cmd_buff(pb); - resume_overlay(pb); - } - planb_unlock(pb); - return 0; - } - case VIDIOCGFBUF: - { - struct video_buffer v; - - DEBUG("PlanB: IOCTL VIDIOCGFBUF\n"); - - v.base = (void *)pb->frame_buffer_phys; - v.height = pb->win.sheight; - v.width = pb->win.swidth; - v.depth = pb->win.depth; - v.bytesperline = pb->win.bpl + pb->win.pad; - if (copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; - return 0; - } - case VIDIOCCAPTURE: - { - int i; - - if(copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - if(i==0) { - DEBUG("PlanB: IOCTL VIDIOCCAPTURE Stop\n"); - - if (!(pb->overlay)) - return 0; - planb_lock(pb); - pb->overlay = 0; - overlay_stop(pb); - planb_unlock(pb); - } else { - DEBUG("PlanB: IOCTL VIDIOCCAPTURE Start\n"); - - if (pb->frame_buffer_phys == 0 || - pb->win.width == 0 || - pb->win.height == 0) - return -EINVAL; - if (pb->overlay) - return 0; - planb_lock(pb); - pb->overlay = 1; - if(!(pb->cmd_buff_inited)) - fill_cmd_buff(pb); - overlay_start(pb); - planb_unlock(pb); - } - return 0; - } - case VIDIOCGCHAN: - { - struct video_channel v; - - DEBUG("PlanB: IOCTL VIDIOCGCHAN\n"); - - if(copy_from_user(&v, arg,sizeof(v))) - return -EFAULT; - v.flags = 0; - v.tuners = 0; - v.type = VIDEO_TYPE_CAMERA; - v.norm = pb->win.norm; - switch(v.channel) - { - case 0: - strcpy(v.name,"Composite"); - break; - case 1: - strcpy(v.name,"SVHS"); - break; - default: - return -EINVAL; - break; - } - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - - return 0; - } - case VIDIOCSCHAN: - { - struct video_channel v; - - DEBUG("PlanB: IOCTL VIDIOCSCHAN\n"); - - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - if (v.norm != pb->win.norm) { - int i, maxlines; - - switch (v.norm) - { - case VIDEO_MODE_PAL: - case VIDEO_MODE_SECAM: - maxlines = PLANB_MAXLINES; - break; - case VIDEO_MODE_NTSC: - maxlines = PLANB_NTSC_MAXLINES; - break; - default: - return -EINVAL; - break; - } - planb_lock(pb); - /* empty the grabbing queue */ - wait_event(pb->capq, !pb->grabbing); - pb->maxlines = maxlines; - pb->win.norm = v.norm; - /* Stop overlay if running */ - suspend_overlay(pb); - for(i = 0; i < MAX_GBUFFERS; i++) - pb->gnorm_switch[i] = 1; - /* I know it's an overkill, but.... */ - fill_cmd_buff(pb); - /* ok, now init it accordingly */ - saa_init_regs (pb); - /* restart overlay if it was running */ - resume_overlay(pb); - planb_unlock(pb); - } - - switch(v.channel) - { - case 0: /* Composite */ - saa_set (SAA7196_IOCC, - ((saa_regs[pb->win.norm][SAA7196_IOCC] & - ~7) | 3), pb); - break; - case 1: /* SVHS */ - saa_set (SAA7196_IOCC, - ((saa_regs[pb->win.norm][SAA7196_IOCC] & - ~7) | 4), pb); - break; - default: - return -EINVAL; - break; - } - - return 0; - } - case VIDIOCGPICT: - { - struct video_picture vp = pb->picture; - - DEBUG("PlanB: IOCTL VIDIOCGPICT\n"); - - switch(pb->win.color_fmt) { - case PLANB_GRAY: - vp.palette = VIDEO_PALETTE_GREY; - case PLANB_COLOUR15: - vp.palette = VIDEO_PALETTE_RGB555; - break; - case PLANB_COLOUR32: - vp.palette = VIDEO_PALETTE_RGB32; - break; - default: - vp.palette = 0; - break; - } - - if(copy_to_user(arg,&vp,sizeof(vp))) - return -EFAULT; - return 0; - } - case VIDIOCSPICT: - { - struct video_picture vp; - - DEBUG("PlanB: IOCTL VIDIOCSPICT\n"); - - if(copy_from_user(&vp,arg,sizeof(vp))) - return -EFAULT; - pb->picture = vp; - /* Should we do sanity checks here? */ - saa_set (SAA7196_BRIG, (unsigned char) - ((pb->picture.brightness) >> 8), pb); - saa_set (SAA7196_HUEC, (unsigned char) - ((pb->picture.hue) >> 8) ^ 0x80, pb); - saa_set (SAA7196_CSAT, (unsigned char) - ((pb->picture.colour) >> 9), pb); - saa_set (SAA7196_CONT, (unsigned char) - ((pb->picture.contrast) >> 9), pb); - - return 0; - } - case VIDIOCSWIN: - { - struct video_window vw; - struct video_clip clip; - int i; - - DEBUG("PlanB: IOCTL VIDIOCSWIN\n"); - - if(copy_from_user(&vw,arg,sizeof(vw))) - return -EFAULT; - - planb_lock(pb); - /* Stop overlay if running */ - suspend_overlay(pb); - pb->win.interlace = (vw.height > pb->maxlines/2)? 1: 0; - if (pb->win.x != vw.x || - pb->win.y != vw.y || - pb->win.width != vw.width || - pb->win.height != vw.height || - !pb->cmd_buff_inited) { - pb->win.x = vw.x; - pb->win.y = vw.y; - pb->win.width = vw.width; - pb->win.height = vw.height; - fill_cmd_buff(pb); - } - /* Reset clip mask */ - memset ((void *) pb->mask, 0xff, (pb->maxlines - * ((PLANB_MAXPIXELS + 7) & ~7)) / 8); - /* Add any clip rects */ - for (i = 0; i < vw.clipcount; i++) { - if (copy_from_user(&clip, vw.clips + i, - sizeof(struct video_clip))) - return -EFAULT; - add_clip(pb, &clip); - } - /* restart overlay if it was running */ - resume_overlay(pb); - planb_unlock(pb); - return 0; - } - case VIDIOCGWIN: - { - struct video_window vw; - - DEBUG("PlanB: IOCTL VIDIOCGWIN\n"); - - vw.x=pb->win.x; - vw.y=pb->win.y; - vw.width=pb->win.width; - vw.height=pb->win.height; - vw.chromakey=0; - vw.flags=0; - if(pb->win.interlace) - vw.flags|=VIDEO_WINDOW_INTERLACE; - if(copy_to_user(arg,&vw,sizeof(vw))) - return -EFAULT; - return 0; - } - case VIDIOCSYNC: { - int i; - - IDEBUG("PlanB: IOCTL VIDIOCSYNC\n"); - - if(copy_from_user((void *)&i,arg,sizeof(int))) - return -EFAULT; - - IDEBUG("PlanB: sync to frame %d\n", i); - - if(i > (MAX_GBUFFERS - 1) || i < 0) - return -EINVAL; -chk_grab: - switch (pb->frame_stat[i]) { - case GBUFFER_UNUSED: - return -EINVAL; - case GBUFFER_GRABBING: - IDEBUG("PlanB: waiting for grab" - " done (%d)\n", i); - interruptible_sleep_on(&pb->capq); - if(signal_pending(current)) - return -EINTR; - goto chk_grab; - case GBUFFER_DONE: - pb->frame_stat[i] = GBUFFER_UNUSED; - break; - } - return 0; - } - - case VIDIOCMCAPTURE: - { - struct video_mmap vm; - volatile unsigned int status; - - IDEBUG("PlanB: IOCTL VIDIOCMCAPTURE\n"); - - if(copy_from_user((void *) &vm,(void *)arg,sizeof(vm))) - return -EFAULT; - status = pb->frame_stat[vm.frame]; - if (status != GBUFFER_UNUSED) - return -EBUSY; - - return vgrab(pb, &vm); - } - - case VIDIOCGMBUF: - { - int i; - struct video_mbuf vm; - - DEBUG("PlanB: IOCTL VIDIOCGMBUF\n"); - - memset(&vm, 0 , sizeof(vm)); - vm.size = PLANB_MAX_FBUF * MAX_GBUFFERS; - vm.frames = MAX_GBUFFERS; - for(i = 0; i<MAX_GBUFFERS; i++) - vm.offsets[i] = PLANB_MAX_FBUF * i; - if(copy_to_user((void *)arg, (void *)&vm, sizeof(vm))) - return -EFAULT; - return 0; - } - - case PLANBIOCGSAAREGS: - { - struct planb_saa_regs preg; - - DEBUG("PlanB: IOCTL PLANBIOCGSAAREGS\n"); - - if(copy_from_user(&preg, arg, sizeof(preg))) - return -EFAULT; - if(preg.addr >= SAA7196_NUMREGS) - return -EINVAL; - preg.val = saa_regs[pb->win.norm][preg.addr]; - if(copy_to_user((void *)arg, (void *)&preg, - sizeof(preg))) - return -EFAULT; - return 0; - } - - case PLANBIOCSSAAREGS: - { - struct planb_saa_regs preg; - - DEBUG("PlanB: IOCTL PLANBIOCSSAAREGS\n"); - - if(copy_from_user(&preg, arg, sizeof(preg))) - return -EFAULT; - if(preg.addr >= SAA7196_NUMREGS) - return -EINVAL; - saa_set (preg.addr, preg.val, pb); - return 0; - } - - case PLANBIOCGSTAT: - { - struct planb_stat_regs pstat; - - DEBUG("PlanB: IOCTL PLANBIOCGSTAT\n"); - - pstat.ch1_stat = in_le32(&pb->planb_base->ch1.status); - pstat.ch2_stat = in_le32(&pb->planb_base->ch2.status); - pstat.saa_stat0 = saa_status(0, pb); - pstat.saa_stat1 = saa_status(1, pb); - - if(copy_to_user((void *)arg, (void *)&pstat, - sizeof(pstat))) - return -EFAULT; - return 0; - } - - case PLANBIOCSMODE: { - int v; - - DEBUG("PlanB: IOCTL PLANBIOCSMODE\n"); - - if(copy_from_user(&v, arg, sizeof(v))) - return -EFAULT; - - switch(v) - { - case PLANB_TV_MODE: - saa_set (SAA7196_STDC, - (saa_regs[pb->win.norm][SAA7196_STDC] & - 0x7f), pb); - break; - case PLANB_VTR_MODE: - saa_set (SAA7196_STDC, - (saa_regs[pb->win.norm][SAA7196_STDC] | - 0x80), pb); - break; - default: - return -EINVAL; - break; - } - pb->win.mode = v; - return 0; - } - case PLANBIOCGMODE: { - int v=pb->win.mode; - - DEBUG("PlanB: IOCTL PLANBIOCGMODE\n"); - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } -#ifdef PLANB_GSCANLINE - case PLANBG_GRAB_BPL: { - int v=pb->gbytes_per_line; - - DEBUG("PlanB: IOCTL PLANBG_GRAB_BPL\n"); - - if(copy_to_user(arg,&v,sizeof(v))) - return -EFAULT; - return 0; - } -#endif /* PLANB_GSCANLINE */ - case PLANB_INTR_DEBUG: { - int i; - - DEBUG("PlanB: IOCTL PLANB_INTR_DEBUG\n"); - - if(copy_from_user(&i, arg, sizeof(i))) - return -EFAULT; - - /* avoid hang ups all together */ - for (i = 0; i < MAX_GBUFFERS; i++) { - if(pb->frame_stat[i] == GBUFFER_GRABBING) { - pb->frame_stat[i] = GBUFFER_DONE; - } - } - if(pb->grabbing) - pb->grabbing--; - wake_up_interruptible(&pb->capq); - return 0; - } - case PLANB_INV_REGS: { - int i; - struct planb_any_regs any; - - DEBUG("PlanB: IOCTL PLANB_INV_REGS\n"); - - if(copy_from_user(&any, arg, sizeof(any))) - return -EFAULT; - if(any.offset < 0 || any.offset + any.bytes > 0x400) - return -EINVAL; - if(any.bytes > 128) - return -EINVAL; - for (i = 0; i < any.bytes; i++) { - any.data[i] = - in_8((unsigned char *)pb->planb_base - + any.offset + i); - } - if(copy_to_user(arg,&any,sizeof(any))) - return -EFAULT; - return 0; - } - default: - { - DEBUG("PlanB: Unimplemented IOCTL\n"); - return -ENOIOCTLCMD; - } - /* Some IOCTLs are currently unsupported on PlanB */ - case VIDIOCGTUNER: { - DEBUG("PlanB: IOCTL VIDIOCGTUNER\n"); - goto unimplemented; } - case VIDIOCSTUNER: { - DEBUG("PlanB: IOCTL VIDIOCSTUNER\n"); - goto unimplemented; } - case VIDIOCSFREQ: { - DEBUG("PlanB: IOCTL VIDIOCSFREQ\n"); - goto unimplemented; } - case VIDIOCGFREQ: { - DEBUG("PlanB: IOCTL VIDIOCGFREQ\n"); - goto unimplemented; } - case VIDIOCKEY: { - DEBUG("PlanB: IOCTL VIDIOCKEY\n"); - goto unimplemented; } - case VIDIOCSAUDIO: { - DEBUG("PlanB: IOCTL VIDIOCSAUDIO\n"); - goto unimplemented; } - case VIDIOCGAUDIO: { - DEBUG("PlanB: IOCTL VIDIOCGAUDIO\n"); - goto unimplemented; } -unimplemented: - DEBUG(" Unimplemented\n"); - return -ENOIOCTLCMD; - } - return 0; -} - -static int planb_mmap(struct vm_area_struct *vma, struct video_device *dev, const char *adr, unsigned long size) -{ - int i; - struct planb *pb = (struct planb *)dev; - unsigned long start = (unsigned long)adr; - - if (size > MAX_GBUFFERS * PLANB_MAX_FBUF) - return -EINVAL; - if (!pb->rawbuf) { - int err; - if((err=grabbuf_alloc(pb))) - return err; - } - for (i = 0; i < pb->rawbuf_size; i++) { - unsigned long pfn; - - pfn = virt_to_phys((void *)pb->rawbuf[i]) >> PAGE_SHIFT; - if (remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start += PAGE_SIZE; - if (size <= PAGE_SIZE) - break; - size -= PAGE_SIZE; - } - return 0; -} - -static struct video_device planb_template= -{ - .owner = THIS_MODULE, - .name = PLANB_DEVICE_NAME, - .type = VID_TYPE_OVERLAY, - .open = planb_open, - .close = planb_close, - .read = planb_read, - .write = planb_write, - .ioctl = planb_ioctl, - .mmap = planb_mmap, /* mmap? */ -}; - -static int init_planb(struct planb *pb) -{ - unsigned char saa_rev; - int i, result; - - memset ((void *) &pb->win, 0, sizeof (struct planb_window)); - /* Simple sanity check */ - if(def_norm >= NUM_SUPPORTED_NORM || def_norm < 0) { - printk(KERN_ERR "PlanB: Option(s) invalid\n"); - return -2; - } - pb->win.norm = def_norm; - pb->win.mode = PLANB_TV_MODE; /* TV mode */ - pb->win.interlace=1; - pb->win.x=0; - pb->win.y=0; - pb->win.width=768; /* 640 */ - pb->win.height=576; /* 480 */ - pb->maxlines=576; -#if 0 /* keep */; - btv->win.cropwidth=768; /* 640 */ - btv->win.cropheight=576; /* 480 */ - btv->win.cropx=0; - btv->win.cropy=0; -#endif - pb->win.pad=0; - pb->win.bpp=4; - pb->win.depth=32; - pb->win.color_fmt=PLANB_COLOUR32; - pb->win.bpl=1024*pb->win.bpp; - pb->win.swidth=1024; - pb->win.sheight=768; -#ifdef PLANB_GSCANLINE - if((pb->gbytes_per_line = PLANB_MAXPIXELS * 4) > PAGE_SIZE - || (pb->gbytes_per_line <= 0)) - return -3; - else { - /* page align pb->gbytes_per_line for DMA purpose */ - for(i = PAGE_SIZE; pb->gbytes_per_line < (i>>1);) - i>>=1; - pb->gbytes_per_line = i; - } -#endif - pb->tab_size = PLANB_MAXLINES + 40; - pb->suspend = 0; - mutex_init(&pb->lock); - pb->ch1_cmd = 0; - pb->ch2_cmd = 0; - pb->mask = 0; - pb->priv_space = 0; - pb->offset = 0; - pb->user = 0; - pb->overlay = 0; - init_waitqueue_head(&pb->suspendq); - pb->cmd_buff_inited = 0; - pb->frame_buffer_phys = 0; - - /* Reset DMA controllers */ - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - - saa_rev = (saa_status(0, pb) & 0xf0) >> 4; - printk(KERN_INFO "PlanB: SAA7196 video processor rev. %d\n", saa_rev); - /* Initialize the SAA registers in memory and on chip */ - saa_init_regs (pb); - - /* clear interrupt mask */ - pb->intr_mask = PLANB_CLR_IRQ; - - result = request_irq(pb->irq, planb_irq, 0, "PlanB", pb); - if (result < 0) { - if (result==-EINVAL) - printk(KERN_ERR "PlanB: Bad irq number (%d) " - "or handler\n", (int)pb->irq); - else if (result==-EBUSY) - printk(KERN_ERR "PlanB: I don't know why, " - "but IRQ %d is busy\n", (int)pb->irq); - return result; - } - disable_irq(pb->irq); - - /* Now add the template and register the device unit. */ - memcpy(&pb->video_dev,&planb_template,sizeof(planb_template)); - - pb->picture.brightness=0x90<<8; - pb->picture.contrast = 0x70 << 8; - pb->picture.colour = 0x70<<8; - pb->picture.hue = 0x8000; - pb->picture.whiteness = 0; - pb->picture.depth = pb->win.depth; - - pb->frame_stat=NULL; - init_waitqueue_head(&pb->capq); - for(i=0; i<MAX_GBUFFERS; i++) { - pb->gbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE; - pb->gwidth[i]=0; - pb->gheight[i]=0; - pb->gfmt[i]=0; - pb->cap_cmd[i]=NULL; -#ifndef PLANB_GSCANLINE - pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF - / PAGE_SIZE + 1) + MAX_LNUM * i; - pb->lsize[i] = 0; - pb->lnum[i] = 0; -#endif - } - pb->rawbuf=NULL; - pb->grabbing=0; - - /* enable interrupts */ - out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - pb->intr_mask = PLANB_FRM_IRQ; - enable_irq(pb->irq); - - if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER, video_nr)<0) - return -1; - - return 0; -} - -/* - * Scan for a PlanB controller, request the irq and map the io memory - */ - -static int find_planb(void) -{ - struct planb *pb; - struct device_node *planb_devices; - unsigned char dev_fn, confreg, bus; - unsigned int old_base, new_base; - unsigned int irq; - struct pci_dev *pdev; - int rc; - - if (!machine_is(powermac)) - return 0; - - planb_devices = of_find_node_by_name(NULL, "planb"); - if (planb_devices == 0) { - planb_num=0; - printk(KERN_WARNING "PlanB: no device found!\n"); - return planb_num; - } - - if (planb_devices->next != NULL) - printk(KERN_ERR "Warning: only using first PlanB device!\n"); - pb = &planbs[0]; - planb_num = 1; - - if (planb_devices->n_addrs != 1) { - printk (KERN_WARNING "PlanB: expecting 1 address for planb " - "(got %d)", planb_devices->n_addrs); - of_node_put(planb_devices); - return 0; - } - - if (planb_devices->n_intrs == 0) { - printk(KERN_WARNING "PlanB: no intrs for device %s\n", - planb_devices->full_name); - of_node_put(planb_devices); - return 0; - } else { - irq = planb_devices->intrs[0].line; - } - - /* Initialize PlanB's PCI registers */ - - /* There is a bug with the way OF assigns addresses - to the devices behind the chaos bridge. - control needs only 0x1000 of space, but decodes only - the upper 16 bits. It therefore occupies a full 64K. - OF assigns the planb controller memory within this space; - so we need to change that here in order to access planb. */ - - /* We remap to 0xf1000000 in hope that nobody uses it ! */ - - bus = (planb_devices->addrs[0].space >> 16) & 0xff; - dev_fn = (planb_devices->addrs[0].space >> 8) & 0xff; - confreg = planb_devices->addrs[0].space & 0xff; - old_base = planb_devices->addrs[0].address; - new_base = 0xf1000000; - of_node_put(planb_devices); - - DEBUG("PlanB: Found on bus %d, dev %d, func %d, " - "membase 0x%x (base reg. 0x%x)\n", - bus, PCI_SLOT(dev_fn), PCI_FUNC(dev_fn), old_base, confreg); - - pdev = pci_get_bus_and_slot(bus, dev_fn); - if (!pdev) { - printk(KERN_ERR "planb: cannot find slot\n"); - goto err_out; - } - - /* Enable response in memory space, bus mastering, - use memory write and invalidate */ - rc = pci_enable_device(pdev); - if (rc) { - printk(KERN_ERR "planb: cannot enable PCI device %s\n", - pci_name(pdev)); - goto err_out; - } - rc = pci_set_mwi(pdev); - if (rc) { - printk(KERN_ERR "planb: cannot enable MWI on PCI device %s\n", - pci_name(pdev)); - goto err_out_disable; - } - pci_set_master(pdev); - - /* Set the new base address */ - pci_write_config_dword (pdev, confreg, new_base); - - planb_regs = (volatile struct planb_registers *) - ioremap (new_base, 0x400); - pb->planb_base = planb_regs; - pb->planb_base_phys = (struct planb_registers *)new_base; - pb->irq = irq; - pb->dev = pdev; - - return planb_num; - -err_out_disable: - pci_disable_device(pdev); -err_out: - /* FIXME handle error */ /* comment moved from pci_find_slot, above */ - pci_dev_put(pdev); - return 0; -} - -static void release_planb(void) -{ - int i; - struct planb *pb; - - for (i=0;i<planb_num; i++) - { - pb=&planbs[i]; - - /* stop and flash DMAs unconditionally */ - planb_dbdma_stop(&pb->planb_base->ch2); - planb_dbdma_stop(&pb->planb_base->ch1); - - /* clear and free interrupts */ - pb->intr_mask = PLANB_CLR_IRQ; - out_le32 (&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - free_irq(pb->irq, pb); - - /* make sure all allocated memory are freed */ - planb_prepare_close(pb); - - printk(KERN_INFO "PlanB: unregistering with v4l\n"); - video_unregister_device(&pb->video_dev); - - pci_dev_put(pb->dev); - - /* note that iounmap() does nothing on the PPC right now */ - iounmap ((void *)pb->planb_base); - } -} - -static int __init init_planbs(void) -{ - int i; - - if (find_planb()<=0) - return -EIO; - - for (i=0; i<planb_num; i++) { - if (init_planb(&planbs[i])<0) { - printk(KERN_ERR "PlanB: error registering device %d" - " with v4l\n", i); - release_planb(); - return -EIO; - } - printk(KERN_INFO "PlanB: registered device %d with v4l\n", i); - } - return 0; -} - -static void __exit exit_planbs(void) -{ - release_planb(); -} - -module_init(init_planbs); -module_exit(exit_planbs); diff --git a/linux/drivers/media/video/planb.h b/linux/drivers/media/video/planb.h deleted file mode 100644 index e21b5735c..000000000 --- a/linux/drivers/media/video/planb.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - planb - PlanB frame grabber driver - - PlanB is used in the 7x00/8x00 series of PowerMacintosh - Computers as video input DMA controller. - - Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) - - Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) - - Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu) - - - 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. -*/ - -/* $Id: planb.h,v 1.13 1999/05/03 19:28:56 mlan Exp $ */ - -#ifndef _PLANB_H_ -#define _PLANB_H_ - -#ifdef __KERNEL__ -#include <asm/dbdma.h> -#include "saa7196.h" -#endif /* __KERNEL__ */ - -#define PLANB_DEVICE_NAME "Apple PlanB Video-In" -#define PLANB_REV "1.0" - -#ifdef __KERNEL__ -//#define PLANB_GSCANLINE /* use this if apps have the notion of */ - /* grab buffer scanline */ -/* This should be safe for both PAL and NTSC */ -#define PLANB_MAXPIXELS 768 -#define PLANB_MAXLINES 576 -#define PLANB_NTSC_MAXLINES 480 - -/* Uncomment your preferred norm ;-) */ -#define PLANB_DEF_NORM VIDEO_MODE_PAL -//#define PLANB_DEF_NORM VIDEO_MODE_NTSC -//#define PLANB_DEF_NORM VIDEO_MODE_SECAM - -/* fields settings */ -#define PLANB_GRAY 0x1 /* 8-bit mono? */ -#define PLANB_COLOUR15 0x2 /* 16-bit mode */ -#define PLANB_COLOUR32 0x4 /* 32-bit mode */ -#define PLANB_CLIPMASK 0x8 /* hardware clipmasking */ - -/* misc. flags for PlanB DMA operation */ -#define CH_SYNC 0x1 /* synchronize channels (set by ch1; - cleared by ch2) */ -#define FIELD_SYNC 0x2 /* used for the start of each field - (0 -> 1 -> 0 for ch1; 0 -> 1 for ch2) */ -#define EVEN_FIELD 0x0 /* even field is detected if unset */ -#define DMA_ABORT 0x2 /* error or just out of sync if set */ -#define ODD_FIELD 0x4 /* odd field is detected if set */ - -/* for capture operations */ -#define MAX_GBUFFERS 2 -/* note PLANB_MAX_FBUF must be divisible by PAGE_SIZE */ -#ifdef PLANB_GSCANLINE -#define PLANB_MAX_FBUF 0x240000 /* 576 * 1024 * 4 */ -#define TAB_FACTOR (1) -#else -#define PLANB_MAX_FBUF 0x1b0000 /* 576 * 768 * 4 */ -#define TAB_FACTOR (2) -#endif -#endif /* __KERNEL__ */ - -struct planb_saa_regs { - unsigned char addr; - unsigned char val; -}; - -struct planb_stat_regs { - unsigned int ch1_stat; - unsigned int ch2_stat; - unsigned char saa_stat0; - unsigned char saa_stat1; -}; - -struct planb_any_regs { - unsigned int offset; - unsigned int bytes; - unsigned char data[128]; -}; - -/* planb private ioctls */ -#define PLANBIOCGSAAREGS _IOWR('v', BASE_VIDIOCPRIVATE, struct planb_saa_regs) /* Read a saa7196 reg value */ -#define PLANBIOCSSAAREGS _IOW('v', BASE_VIDIOCPRIVATE + 1, struct planb_saa_regs) /* Set a saa7196 reg value */ -#define PLANBIOCGSTAT _IOR('v', BASE_VIDIOCPRIVATE + 2, struct planb_stat_regs) /* Read planb status */ -#define PLANB_TV_MODE 1 -#define PLANB_VTR_MODE 2 -#define PLANBIOCGMODE _IOR('v', BASE_VIDIOCPRIVATE + 3, int) /* Get TV/VTR mode */ -#define PLANBIOCSMODE _IOW('v', BASE_VIDIOCPRIVATE + 4, int) /* Set TV/VTR mode */ - -#ifdef PLANB_GSCANLINE -#define PLANBG_GRAB_BPL _IOR('v', BASE_VIDIOCPRIVATE + 5, int) /* # of bytes per scanline in grab buffer */ -#endif - -/* call wake_up_interruptible() with appropriate actions */ -#define PLANB_INTR_DEBUG _IOW('v', BASE_VIDIOCPRIVATE + 20, int) -/* investigate which reg does what */ -#define PLANB_INV_REGS _IOWR('v', BASE_VIDIOCPRIVATE + 21, struct planb_any_regs) - -#ifdef __KERNEL__ - -/* Potentially useful macros */ -#define PLANB_SET(x) ((x) << 16 | (x)) -#define PLANB_CLR(x) ((x) << 16) - -/* This represents the physical register layout */ -struct planb_registers { - volatile struct dbdma_regs ch1; /* 0x00: video in */ - volatile unsigned int even; /* 0x40: even field setting */ - volatile unsigned int odd; /* 0x44; odd field setting */ - unsigned int pad1[14]; /* empty? */ - volatile struct dbdma_regs ch2; /* 0x80: clipmask out */ - unsigned int pad2[16]; /* 0xc0: empty? */ - volatile unsigned int reg3; /* 0x100: ???? */ - volatile unsigned int intr_stat; /* 0x104: irq status */ -#define PLANB_CLR_IRQ 0x00 /* clear Plan B interrupt */ -#define PLANB_GEN_IRQ 0x01 /* assert Plan B interrupt */ -#define PLANB_FRM_IRQ 0x0100 /* end of frame */ - unsigned int pad3[1]; /* empty? */ - volatile unsigned int reg5; /* 0x10c: ??? */ - unsigned int pad4[60]; /* empty? */ - volatile unsigned char saa_addr; /* 0x200: SAA subadr */ - char pad5[3]; - volatile unsigned char saa_regval; /* SAA7196 write reg. val */ - char pad6[3]; - volatile unsigned char saa_status; /* SAA7196 status byte */ - /* There is more unused stuff here */ -}; - -struct planb_window { - int x, y; - ushort width, height; - ushort bpp, bpl, depth, pad; - ushort swidth, sheight; - int norm; - int interlace; - u32 color_fmt; - int chromakey; - int mode; /* used to switch between TV/VTR modes */ -}; - -struct planb_suspend { - int overlay; - int frame; - struct dbdma_cmd cmd; -}; - -struct planb { - struct video_device video_dev; - struct video_picture picture; /* Current picture params */ - struct video_audio audio_dev; /* Current audio params */ - - volatile struct planb_registers *planb_base; /* virt base of planb */ - struct planb_registers *planb_base_phys; /* phys base of planb */ - void *priv_space; /* Org. alloc. mem for kfree */ - int user; - unsigned int tab_size; - int maxlines; - struct mutex lock; - unsigned int irq; /* interrupt number */ - volatile unsigned int intr_mask; - struct pci_dev *dev; /* Our PCI device */ - - int overlay; /* overlay running? */ - struct planb_window win; - unsigned long frame_buffer_phys; /* We need phys for DMA */ - int offset; /* offset of pixel 1 */ - volatile struct dbdma_cmd *ch1_cmd; /* Video In DMA cmd buffer */ - volatile struct dbdma_cmd *ch2_cmd; /* Clip Out DMA cmd buffer */ - volatile struct dbdma_cmd *overlay_last1; - volatile struct dbdma_cmd *overlay_last2; - unsigned long ch1_cmd_phys; - volatile unsigned char *mask; /* Clipmask buffer */ - int suspend; - wait_queue_head_t suspendq; - struct planb_suspend suspended; - int cmd_buff_inited; /* cmd buffer inited? */ - - int grabbing; - unsigned int gcount; - wait_queue_head_t capq; - int last_fr; - int prev_last_fr; - unsigned char **rawbuf; - int rawbuf_size; - int gbuf_idx[MAX_GBUFFERS]; - volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS]; - volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS]; - volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS]; - int need_pre_capture[MAX_GBUFFERS]; -#define PLANB_DUMMY 40 /* # of command buf's allocated for pre-capture seq. */ - int gwidth[MAX_GBUFFERS], gheight[MAX_GBUFFERS]; - unsigned int gfmt[MAX_GBUFFERS]; - int gnorm_switch[MAX_GBUFFERS]; - volatile unsigned int *frame_stat; -#define GBUFFER_UNUSED 0x00U -#define GBUFFER_GRABBING 0x01U -#define GBUFFER_DONE 0x02U -#ifdef PLANB_GSCANLINE - int gbytes_per_line; -#else -#define MAX_LNUM 431 /* change this if PLANB_MAXLINES or */ - /* PLANB_MAXPIXELS changes */ - int l_fr_addr_idx[MAX_GBUFFERS]; - unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM]; - int l_to_next_idx[MAX_GBUFFERS][MAX_LNUM]; - int l_to_next_size[MAX_GBUFFERS][MAX_LNUM]; - int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS]; -#endif -}; - -#endif /* __KERNEL__ */ - -#endif /* _PLANB_H_ */ diff --git a/linux/drivers/media/video/pms.c b/linux/drivers/media/video/pms.c index 31d8a929f..e36b39b44 100644 --- a/linux/drivers/media/video/pms.c +++ b/linux/drivers/media/video/pms.c @@ -896,9 +896,7 @@ static const struct file_operations pms_fops = { static struct video_device pms_template= { - .owner = THIS_MODULE, .name = "Mediavision PMS", - .type = VID_TYPE_CAPTURE, .fops = &pms_fops, }; diff --git a/linux/drivers/media/video/pvrusb2/Kconfig b/linux/drivers/media/video/pvrusb2/Kconfig index 4482b2c72..19eb274c9 100644 --- a/linux/drivers/media/video/pvrusb2/Kconfig +++ b/linux/drivers/media/video/pvrusb2/Kconfig @@ -2,8 +2,6 @@ config VIDEO_PVRUSB2 tristate "Hauppauge WinTV-PVR USB2 support" depends on VIDEO_V4L2 && I2C depends on VIDEO_MEDIA # Avoids pvrusb = Y / DVB = M - depends on HOTPLUG # due to FW_LOADER - select FW_LOADER select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-context.h b/linux/drivers/media/video/pvrusb2/pvrusb2-context.h index 61801291c..d657e53bb 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-context.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-context.h @@ -16,8 +16,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ -#ifndef __PVRUSB2_BASE_H -#define __PVRUSB2_BASE_H +#ifndef __PVRUSB2_CONTEXT_H +#define __PVRUSB2_CONTEXT_H #include <linux/mutex.h> #include <linux/usb.h> diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 5d036e7e3..88e175168 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -97,13 +97,13 @@ static const struct pvr2_device_desc pvr2_device_24xxx = { .flag_has_cx25840 = !0, .flag_has_wm8775 = !0, .flag_has_hauppauge_rom = !0, - .flag_has_hauppauge_custom_ir = !0, .flag_has_analogtuner = !0, .flag_has_fmradio = !0, .flag_has_composite = !0, .flag_has_svideo = !0, .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_24XXX, }; @@ -330,7 +330,7 @@ static const char *pvr2_fw1_names_73xxx[] = { }; static const struct pvr2_device_desc pvr2_device_73xxx = { - .description = "WinTV PVR USB2 Model Category 73xxx", + .description = "WinTV HVR-1900 Model Category 73xxx", .shortname = "73xxx", .client_modules.lst = pvr2_client_73xxx, .client_modules.cnt = ARRAY_SIZE(pvr2_client_73xxx), @@ -344,6 +344,7 @@ static const struct pvr2_device_desc pvr2_device_73xxx = { .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE, .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_ZILOG, #ifdef CONFIG_VIDEO_PVRUSB2_DVB .dvb_props = &pvr2_73xxx_dvb_props, #endif @@ -438,7 +439,7 @@ static const char *pvr2_fw1_names_75xxx[] = { }; static const struct pvr2_device_desc pvr2_device_750xx = { - .description = "WinTV PVR USB2 Model Category 750xx", + .description = "WinTV HVR-1950 Model Category 750xx", .shortname = "750xx", .client_modules.lst = pvr2_client_75xxx, .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx), @@ -453,13 +454,14 @@ static const struct pvr2_device_desc pvr2_device_750xx = { .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, .default_std_mask = V4L2_STD_NTSC_M, .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_ZILOG, #ifdef CONFIG_VIDEO_PVRUSB2_DVB .dvb_props = &pvr2_750xx_dvb_props, #endif }; static const struct pvr2_device_desc pvr2_device_751xx = { - .description = "WinTV PVR USB2 Model Category 751xx", + .description = "WinTV HVR-1950 Model Category 751xx", .shortname = "751xx", .client_modules.lst = pvr2_client_75xxx, .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx), @@ -474,6 +476,7 @@ static const struct pvr2_device_desc pvr2_device_751xx = { .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE, .default_std_mask = V4L2_STD_NTSC_M, .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE, + .ir_scheme = PVR2_IR_SCHEME_ZILOG, #ifdef CONFIG_VIDEO_PVRUSB2_DVB .dvb_props = &pvr2_751xx_dvb_props, #endif diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h index e23ce1d2e..cb3a33eb0 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.h @@ -48,6 +48,10 @@ struct pvr2_string_table { #define PVR2_LED_SCHEME_NONE 0 #define PVR2_LED_SCHEME_HAUPPAUGE 1 +#define PVR2_IR_SCHEME_NONE 0 +#define PVR2_IR_SCHEME_24XXX 1 +#define PVR2_IR_SCHEME_ZILOG 2 + /* This describes a particular hardware type (except for the USB device ID which must live in a separate structure due to environmental constraints). See the top of pvrusb2-hdw.c for where this is @@ -126,15 +130,19 @@ struct pvr2_device_desc { ensure that it is found. */ unsigned int flag_has_wm8775:1; - /* Device has IR hardware that can be faked into looking like a - normal Hauppauge i2c IR receiver. This is currently very - specific to the 24xxx device, where Hauppauge had replaced their - 'standard' I2C IR receiver with a bunch of FPGA logic controlled - directly via the FX2. Turning this on tells the pvrusb2 driver - to virtualize the presence of the non-existant IR receiver chip and - implement the virtual receiver in terms of appropriate FX2 - commands. */ - unsigned int flag_has_hauppauge_custom_ir:1; + /* Indicate any specialized IR scheme that might need to be + supported by this driver. If not set, then it is assumed that + IR can work without help from the driver (which is frequently + the case). This is otherwise set to one of + PVR2_IR_SCHEME_xxxx. For "xxxx", the value "24XXX" indicates a + Hauppauge 24xxx class device which has an FPGA-hosted IR + receiver that can only be reached via FX2 command codes. In + that case the pvrusb2 driver will emulate the behavior of the + older 29xxx device's IR receiver (a "virtual" I2C chip) in terms + of those command codes. For the value "ZILOG", we're dealing + with an IR chip that must be taken out of reset via another FX2 + command code (which is the case for HVR-1950 devices). */ + unsigned int ir_scheme:2; /* These bits define which kinds of sources the device can handle. Note: Digital tuner presence is inferred by the diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c index a317347ad..29d18e867 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-dvb.c @@ -24,6 +24,7 @@ #else #include <linux/freezer.h> #endif +#include <linux/mm.h> #include "compat.h" #include "dvbdev.h" #include "pvrusb2-debug.h" diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h index b58369e7f..614755ea2 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h @@ -24,6 +24,8 @@ #define FX2CMD_MEM_WRITE_DWORD 0x01u #define FX2CMD_MEM_READ_DWORD 0x02u +#define FX2CMD_HCW_ZILOG_RESET 0x10u /* 1=reset 0=release */ + #define FX2CMD_MEM_READ_64BYTES 0x28u #define FX2CMD_REG_WRITE 0x04u diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c index cbf848e82..419a473cf 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -251,6 +251,7 @@ struct pvr2_fx2cmd_descdef { static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = { {FX2CMD_MEM_WRITE_DWORD, "write encoder dword"}, {FX2CMD_MEM_READ_DWORD, "read encoder dword"}, + {FX2CMD_HCW_ZILOG_RESET, "zilog IR reset control"}, {FX2CMD_MEM_READ_64BYTES, "read encoder 64bytes"}, {FX2CMD_REG_WRITE, "write encoder register"}, {FX2CMD_REG_READ, "read encoder register"}, @@ -1728,6 +1729,14 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) if (!pvr2_hdw_dev_ok(hdw)) return; } + /* Take the IR chip out of reset, if appropriate */ + if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_ZILOG) { + pvr2_issue_simple_cmd(hdw, + FX2CMD_HCW_ZILOG_RESET | + (1 << 8) | + ((0) << 16)); + } + // This step MUST happen after the earlier powerup step. pvr2_i2c_core_init(hdw); if (!pvr2_hdw_dev_ok(hdw)) return; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index ef741d1fc..9159686c3 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -1054,7 +1054,9 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) printk(KERN_INFO "%s: IR disabled\n",hdw->name); hdw->i2c_func[0x18] = i2c_black_hole; } else if (ir_mode[hdw->unit_number] == 1) { - if (hdw->hdw_desc->flag_has_hauppauge_custom_ir) { + if (hdw->hdw_desc->ir_scheme == PVR2_IR_SCHEME_24XXX) { + /* This comment is present PURELY to get + checkpatch.pl to STFU. Lovely, eh? */ hdw->i2c_func[0x18] = i2c_24xxx_ir; } } diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c index fa599a1bf..987e71142 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c @@ -22,6 +22,7 @@ #include "pvrusb2-debug.h" #include <linux/errno.h> #include <linux/string.h> +#include <linux/mm.h> #include <linux/slab.h> #include <linux/mutex.h> #include <asm/uaccess.h> diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index f097d6aaf..c1cc0e88b 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -933,6 +933,7 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) unsigned int input_cnt,idx; int ret = 0; + lock_kernel(); dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase); vp = dip->v4lp; @@ -943,11 +944,13 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) if (!pvr2_hdw_dev_ok(hdw)) { pvr2_trace(PVR2_TRACE_OPEN_CLOSE, "pvr2_v4l2_open: hardware not ready"); + unlock_kernel(); return -EIO; } fhp = kzalloc(sizeof(*fhp),GFP_KERNEL); if (!fhp) { + unlock_kernel(); return -ENOMEM; } @@ -977,6 +980,7 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) fhp); kfree(fhp); + unlock_kernel(); return ret; } @@ -993,6 +997,7 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) "Destroying pvr_v4l2_fh id=%p (input map failure)", fhp); kfree(fhp); + unlock_kernel(); return -ENOMEM; } input_cnt = 0; @@ -1016,6 +1021,7 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) v4l2_prio_open(&vp->prio,&fhp->prio); fhp->fw_mode_flag = pvr2_hdw_cpufw_get_enabled(hdw); + unlock_kernel(); return 0; } @@ -1162,11 +1168,6 @@ static const struct file_operations vdev_fops = { static struct video_device vdev_template = { - .owner = THIS_MODULE, - .type = VID_TYPE_CAPTURE | VID_TYPE_TUNER, - .type2 = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE - | V4L2_CAP_TUNER | V4L2_CAP_AUDIO - | V4L2_CAP_READWRITE), .fops = &vdev_fops, }; diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c index e51ee878b..f005e2338 100644 --- a/linux/drivers/media/video/pwc/pwc-if.c +++ b/linux/drivers/media/video/pwc/pwc-if.c @@ -165,9 +165,7 @@ static const struct file_operations pwc_fops = { .llseek = no_llseek, }; static struct video_device pwc_template = { - .owner = THIS_MODULE, .name = "Philips Webcam", /* Filled in later */ - .type = VID_TYPE_CAPTURE, .release = video_device_release, .fops = &pwc_fops, .minor = -1, @@ -1052,19 +1050,20 @@ static int pwc_create_sysfs_files(struct video_device *vdev) struct pwc_device *pdev = video_get_drvdata(vdev); int rc; - rc = video_device_create_file(vdev, &dev_attr_button); + rc = device_create_file(&vdev->dev, &dev_attr_button); if (rc) goto err; if (pdev->features & FEATURE_MOTOR_PANTILT) { - rc = video_device_create_file(vdev, &dev_attr_pan_tilt); + rc = device_create_file(&vdev->dev, &dev_attr_pan_tilt); if (rc) goto err_button; } return 0; err_button: - video_device_remove_file(vdev, &dev_attr_button); + device_remove_file(&vdev->dev, &dev_attr_button); err: + PWC_ERROR("Could not create sysfs files.\n"); return rc; } @@ -1072,8 +1071,8 @@ static void pwc_remove_sysfs_files(struct video_device *vdev) { struct pwc_device *pdev = video_get_drvdata(vdev); if (pdev->features & FEATURE_MOTOR_PANTILT) - video_device_remove_file(vdev, &dev_attr_pan_tilt); - video_device_remove_file(vdev, &dev_attr_button); + device_remove_file(&vdev->dev, &dev_attr_pan_tilt); + device_remove_file(&vdev->dev, &dev_attr_button); } #ifdef CONFIG_USB_PWC_DEBUG @@ -1773,7 +1772,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); pdev->vdev->parent = &(udev->dev); strcpy(pdev->vdev->name, name); - pdev->vdev->owner = THIS_MODULE; video_set_drvdata(pdev->vdev, pdev); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); diff --git a/linux/drivers/media/video/pwc/pwc.h b/linux/drivers/media/video/pwc/pwc.h index 977700416..926defb11 100644 --- a/linux/drivers/media/video/pwc/pwc.h +++ b/linux/drivers/media/video/pwc/pwc.h @@ -32,6 +32,7 @@ #include <linux/smp_lock.h> #include <linux/version.h> #include <linux/mutex.h> +#include <linux/mm.h> #include <asm/errno.h> #include "compat.h" #include <linux/videodev.h> diff --git a/linux/drivers/media/video/pxa_camera.c b/linux/drivers/media/video/pxa_camera.c index b15f82c49..ee2fb7baa 100644 --- a/linux/drivers/media/video/pxa_camera.c +++ b/linux/drivers/media/video/pxa_camera.c @@ -36,8 +36,13 @@ #include <linux/videodev2.h> #include <asm/dma.h> +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) +#include <mach/pxa-regs.h> +#include <mach/camera.h> +#else #include <asm/arch/pxa-regs.h> #include <asm/arch/camera.h> +#endif #define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5) #define PXA_CAM_DRV_NAME "pxa27x-camera" @@ -128,6 +133,8 @@ struct pxa_camera_dev { struct pxa_buffer *active; struct pxa_dma_desc *sg_tail[3]; + + u32 save_cicr[5]; }; static const char *pxa_cam_driver_description = "PXA_Camera"; @@ -627,17 +634,6 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev) pdata->init(pcdev->dev); } - if (pdata && pdata->power) { - dev_dbg(pcdev->dev, "%s: Power on camera\n", __func__); - pdata->power(pcdev->dev, 1); - } - - if (pdata && pdata->reset) { - dev_dbg(pcdev->dev, "%s: Releasing camera reset\n", - __func__); - pdata->reset(pcdev->dev, 1); - } - CICR0 = 0x3FF; /* disable all interrupts */ if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN) @@ -658,20 +654,7 @@ static void pxa_camera_activate(struct pxa_camera_dev *pcdev) static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev) { - struct pxacamera_platform_data *board = pcdev->pdata; - clk_disable(pcdev->clk); - - if (board && board->reset) { - dev_dbg(pcdev->dev, "%s: Asserting camera reset\n", - __func__); - board->reset(pcdev->dev, 0); - } - - if (board && board->power) { - dev_dbg(pcdev->dev, "%s: Power off camera\n", __func__); - board->power(pcdev->dev, 0); - } } static irqreturn_t pxa_camera_irq(int irq, void *data) @@ -997,10 +980,64 @@ static int pxa_camera_querycap(struct soc_camera_host *ici, return 0; } +static int pxa_camera_suspend(struct soc_camera_device *icd, pm_message_t state) +{ + struct soc_camera_host *ici = + to_soc_camera_host(icd->dev.parent); + struct pxa_camera_dev *pcdev = ici->priv; + int i = 0, ret = 0; + + pcdev->save_cicr[i++] = CICR0; + pcdev->save_cicr[i++] = CICR1; + pcdev->save_cicr[i++] = CICR2; + pcdev->save_cicr[i++] = CICR3; + pcdev->save_cicr[i++] = CICR4; + + if ((pcdev->icd) && (pcdev->icd->ops->suspend)) + ret = pcdev->icd->ops->suspend(pcdev->icd, state); + + return ret; +} + +static int pxa_camera_resume(struct soc_camera_device *icd) +{ + struct soc_camera_host *ici = + to_soc_camera_host(icd->dev.parent); + struct pxa_camera_dev *pcdev = ici->priv; + int i = 0, ret = 0; + + DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD; + DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD; + DRCMR70 = pcdev->dma_chans[2] | DRCMR_MAPVLD; + + CICR0 = pcdev->save_cicr[i++] & ~CICR0_ENB; + CICR1 = pcdev->save_cicr[i++]; + CICR2 = pcdev->save_cicr[i++]; + CICR3 = pcdev->save_cicr[i++]; + CICR4 = pcdev->save_cicr[i++]; + + if ((pcdev->icd) && (pcdev->icd->ops->resume)) + ret = pcdev->icd->ops->resume(pcdev->icd); + + /* Restart frame capture if active buffer exists */ + if (!ret && pcdev->active) { + /* Reset the FIFOs */ + CIFR |= CIFR_RESET_F; + /* Enable End-Of-Frame Interrupt */ + CICR0 &= ~CICR0_EOFM; + /* Restart the Capture Interface */ + CICR0 |= CICR0_ENB; + } + + return ret; +} + static struct soc_camera_host_ops pxa_soc_camera_host_ops = { .owner = THIS_MODULE, .add = pxa_camera_add_device, .remove = pxa_camera_remove_device, + .suspend = pxa_camera_suspend, + .resume = pxa_camera_resume, .set_fmt_cap = pxa_camera_set_fmt_cap, .try_fmt_cap = pxa_camera_try_fmt_cap, .init_videobuf = pxa_camera_init_videobuf, @@ -1198,7 +1235,7 @@ static int __devinit pxa_camera_init(void) static void __exit pxa_camera_exit(void) { - return platform_driver_unregister(&pxa_camera_driver); + platform_driver_unregister(&pxa_camera_driver); } module_init(pxa_camera_init); diff --git a/linux/drivers/media/video/s2255drv.c b/linux/drivers/media/video/s2255drv.c index f6516a4e4..939edff48 100644 --- a/linux/drivers/media/video/s2255drv.c +++ b/linux/drivers/media/video/s2255drv.c @@ -47,6 +47,7 @@ #include <linux/mutex.h> #include <linux/videodev2.h> #include <linux/version.h> +#include <linux/mm.h> #include <media/videobuf-vmalloc.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> @@ -186,6 +187,7 @@ struct s2255_dmaqueue { #define S2255_FW_LOADED_DSPWAIT 1 #define S2255_FW_SUCCESS 2 #define S2255_FW_FAILED 3 +#define S2255_FW_DISCONNECTING 4 struct s2255_fw { int fw_loaded; @@ -265,7 +267,6 @@ struct s2255_buffer { struct s2255_fh { struct s2255_dev *dev; - unsigned int resources; const struct s2255_fmt *fmt; unsigned int width; unsigned int height; @@ -275,14 +276,9 @@ struct s2255_fh { /* mode below is the desired mode. mode in s2255_dev is the current mode that was last set */ struct s2255_mode mode; + int resources[MAX_CHANNELS]; }; -/* - * TODO: fixme S2255_MAX_USERS. Do not limit open driver handles. - * Limit V4L to one stream at a time. - */ -#define S2255_MAX_USERS 1 - #define CUR_USB_FWVER 774 /* current cypress EEPROM firmware version */ #define S2255_MAJOR_VERSION 1 #define S2255_MINOR_VERSION 13 @@ -478,10 +474,9 @@ static void s2255_timer(unsigned long user_data) dprintk(100, "s2255 timer\n"); if (usb_submit_urb(data->fw_urb, GFP_ATOMIC) < 0) { printk(KERN_ERR "s2255: can't submit urb\n"); - if (data->fw) { - release_firmware(data->fw); - data->fw = NULL; - } + atomic_set(&data->fw_state, S2255_FW_FAILED); + /* wake up anything waiting for the firmware */ + wake_up(&data->wait_fw); return; } } @@ -511,13 +506,18 @@ static void s2255_fwchunk_complete(struct urb *urb) struct usb_device *udev = urb->dev; int len; dprintk(100, "udev %p urb %p", udev, urb); - /* TODO: fixme. reflect change in status */ if (urb->status) { dev_err(&udev->dev, "URB failed with status %d", urb->status); + atomic_set(&data->fw_state, S2255_FW_FAILED); + /* wake up anything waiting for the firmware */ + wake_up(&data->wait_fw); return; } if (data->fw_urb == NULL) { - dev_err(&udev->dev, "early disconncect\n"); + dev_err(&udev->dev, "s2255 disconnected\n"); + atomic_set(&data->fw_state, S2255_FW_FAILED); + /* wake up anything waiting for the firmware */ + wake_up(&data->wait_fw); return; } #define CHUNK_SIZE 512 @@ -791,7 +791,8 @@ static int res_get(struct s2255_dev *dev, struct s2255_fh *fh) } /* it's free, grab it */ dev->resources[fh->channel] = 1; - dprintk(1, "res: get\n"); + fh->resources[fh->channel] = 1; + dprintk(1, "s2255: res: get\n"); mutex_unlock(&dev->lock); return 1; } @@ -801,9 +802,18 @@ static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh) return dev->resources[fh->channel]; } +static int res_check(struct s2255_fh *fh) +{ + return fh->resources[fh->channel]; +} + + static void res_free(struct s2255_dev *dev, struct s2255_fh *fh) { + mutex_lock(&dev->lock); dev->resources[fh->channel] = 0; + fh->resources[fh->channel] = 0; + mutex_unlock(&dev->lock); dprintk(1, "res: put\n"); } @@ -1234,7 +1244,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) } if (!res_get(dev, fh)) { - dev_err(&dev->udev->dev, "res get busy\n"); + dev_err(&dev->udev->dev, "s2255: stream busy\n"); return -EBUSY; } @@ -1290,8 +1300,10 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) } s2255_stop_acquire(dev, fh->channel); res = videobuf_streamoff(&fh->vb_vidq); + if (res < 0) + return res; res_free(dev, fh); - return res; + return 0; } static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) @@ -1445,6 +1457,7 @@ static int s2255_open(struct inode *inode, struct file *file) int cur_channel = -1; dprintk(1, "s2255: open called (minor=%d)\n", minor); + lock_kernel(); list_for_each(list, &s2255_devlist) { h = list_entry(list, struct s2255_dev, s2255_devlist); for (i = 0; i < MAX_CHANNELS; i++) { @@ -1457,6 +1470,7 @@ static int s2255_open(struct inode *inode, struct file *file) } if ((NULL == dev) || (cur_channel == -1)) { + unlock_kernel(); dprintk(1, "s2255: openv4l no dev\n"); return -ENODEV; } @@ -1464,12 +1478,7 @@ static int s2255_open(struct inode *inode, struct file *file) mutex_lock(&dev->open_lock); dev->users[cur_channel]++; - if (dev->users[cur_channel] > S2255_MAX_USERS) { - dev->users[cur_channel]--; - mutex_unlock(&dev->open_lock); - printk(KERN_INFO "s2255drv: too many open handles!\n"); - return -EBUSY; - } + dprintk(4, "s2255: open_handles %d\n", dev->users[cur_channel]); if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) { err("2255 firmware load failed. retrying.\n"); @@ -1480,8 +1489,10 @@ static int s2255_open(struct inode *inode, struct file *file) msecs_to_jiffies(S2255_LOAD_TIMEOUT)); if (atomic_read(&dev->fw_data->fw_state) != S2255_FW_SUCCESS) { - printk(KERN_INFO "2255 FW load failed after 2 tries\n"); + printk(KERN_INFO "2255 FW load failed.\n"); + dev->users[cur_channel]--; mutex_unlock(&dev->open_lock); + unlock_kernel(); return -EFAULT; } } else if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_NOTLOADED) { @@ -1496,7 +1507,9 @@ static int s2255_open(struct inode *inode, struct file *file) != S2255_FW_SUCCESS) { printk(KERN_INFO "2255 firmware not loaded" "try again\n"); + dev->users[cur_channel]--; mutex_unlock(&dev->open_lock); + unlock_kernel(); return -EBUSY; } } @@ -1504,7 +1517,9 @@ static int s2255_open(struct inode *inode, struct file *file) /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh), GFP_KERNEL); if (NULL == fh) { + dev->users[cur_channel]--; mutex_unlock(&dev->open_lock); + unlock_kernel(); return -ENOMEM; } @@ -1538,6 +1553,7 @@ static int s2255_open(struct inode *inode, struct file *file) kref_get(&dev->kref); mutex_unlock(&dev->open_lock); + unlock_kernel(); return 0; } @@ -1563,44 +1579,48 @@ static void s2255_destroy(struct kref *kref) printk(KERN_ERR "s2255drv: kref problem\n"); return; } + + /* + * Wake up any firmware load waiting (only done in .open, + * which holds the open_lock mutex) + */ + atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING); + wake_up(&dev->fw_data->wait_fw); + /* prevent s2255_disconnect from racing s2255_open */ mutex_lock(&dev->open_lock); s2255_exit_v4l(dev); - /* device unregistered so no longer possible to open. open_mutex - can be unlocked */ + /* + * device unregistered so no longer possible to open. open_mutex + * can be unlocked and timers deleted afterwards. + */ mutex_unlock(&dev->open_lock); /* board shutdown stops the read pipe if it is running */ s2255_board_shutdown(dev); /* make sure firmware still not trying to load */ + del_timer(&dev->timer); /* only started in .probe and .open */ + if (dev->fw_data->fw_urb) { dprintk(2, "kill fw_urb\n"); usb_kill_urb(dev->fw_data->fw_urb); usb_free_urb(dev->fw_data->fw_urb); dev->fw_data->fw_urb = NULL; } + /* - * TODO: fixme(above, below): potentially leaving timers alive. - * do not ignore timeout below if - * it occurs. + * delete the dsp_wait timer, which sets the firmware + * state on completion. This is done before fw_data + * is freed below. */ - /* make sure we aren't waiting for the DSP */ - if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_LOADED_DSPWAIT) { - /* if we are, wait for the wakeup for fw_success or timeout */ - wait_event_timeout(dev->fw_data->wait_fw, - (atomic_read(&dev->fw_data->fw_state) - == S2255_FW_SUCCESS), - msecs_to_jiffies(S2255_LOAD_TIMEOUT)); - } + del_timer(&dev->fw_data->dsp_wait); /* only started in .open */ - if (dev->fw_data) { - if (dev->fw_data->fw) - release_firmware(dev->fw_data->fw); - kfree(dev->fw_data->pfw_data); - kfree(dev->fw_data); - } + if (dev->fw_data->fw) + release_firmware(dev->fw_data->fw); + kfree(dev->fw_data->pfw_data); + kfree(dev->fw_data); usb_put_dev(dev->udev); dprintk(1, "%s", __func__); @@ -1617,17 +1637,23 @@ static int s2255_close(struct inode *inode, struct file *file) mutex_lock(&dev->open_lock); - if (dev->b_acquire[fh->channel]) - s2255_stop_acquire(dev, fh->channel); - res_free(dev, fh); + /* turn off stream */ + if (res_check(fh)) { + if (dev->b_acquire[fh->channel]) + s2255_stop_acquire(dev, fh->channel); + videobuf_streamoff(&fh->vb_vidq); + res_free(dev, fh); + } + videobuf_mmap_free(&fh->vb_vidq); - kfree(fh); dev->users[fh->channel]--; + mutex_unlock(&dev->open_lock); kref_put(&dev->kref, s2255_destroy); dprintk(1, "s2255: close called (minor=%d, users=%d)\n", minor, dev->users[fh->channel]); + kfree(fh); return 0; } @@ -1660,12 +1686,7 @@ static const struct file_operations s2255_fops_v4l = { .llseek = no_llseek, }; -static struct video_device template = { - .name = "s2255v", - .type = VID_TYPE_CAPTURE, - .fops = &s2255_fops_v4l, - .minor = -1, - .release = video_device_release, +static const struct v4l2_ioctl_ops s2255_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1687,6 +1708,14 @@ static struct video_device template = { #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidioc_cgmbuf, #endif +}; + +static struct video_device template = { + .name = "s2255v", + .fops = &s2255_fops_v4l, + .ioctl_ops = &s2255_ioctl_ops, + .minor = -1, + .release = video_device_release, .tvnorms = S2255_NORMS, .current_norm = V4L2_STD_NTSC_M, }; diff --git a/linux/drivers/media/video/saa5246a.c b/linux/drivers/media/video/saa5246a.c index 49b4a046c..1bfc49822 100644 --- a/linux/drivers/media/video/saa5246a.c +++ b/linux/drivers/media/video/saa5246a.c @@ -44,6 +44,7 @@ #include <linux/init.h> #include <linux/i2c.h> #include <linux/videotext.h> +#include <linux/smp_lock.h> #include "compat.h" #include <linux/videodev.h> #include <media/v4l2-common.h> @@ -738,9 +739,12 @@ static int saa5246a_open(struct inode *inode, struct file *file) struct saa5246a_device *t = vd->priv; int err; + lock_kernel(); err = video_exclusive_open(inode,file); - if (err < 0) + if (err < 0) { + unlock_kernel(); return err; + } if (t->client==NULL) { err = -ENODEV; @@ -777,11 +781,13 @@ static int saa5246a_open(struct inode *inode, struct file *file) err = -EIO; goto fail; } + unlock_kernel(); return 0; fail: video_exclusive_release(inode,file); + unlock_kernel(); return err; } @@ -831,9 +837,7 @@ static const struct file_operations saa_fops = { static struct video_device saa_template = { - .owner = THIS_MODULE, .name = IF_NAME, - .type = VID_TYPE_TELETEXT, .fops = &saa_fops, .release = video_device_release, .minor = -1, diff --git a/linux/drivers/media/video/saa5249.c b/linux/drivers/media/video/saa5249.c index 6423a6762..81d341a80 100644 --- a/linux/drivers/media/video/saa5249.c +++ b/linux/drivers/media/video/saa5249.c @@ -52,6 +52,7 @@ #include <linux/ioport.h> #include <linux/slab.h> #include <linux/init.h> +#include <linux/smp_lock.h> #include <stdarg.h> #include <linux/i2c.h> #include <linux/videotext.h> @@ -634,9 +635,12 @@ static int saa5249_open(struct inode *inode, struct file *file) struct saa5249_device *t=vd->priv; int err,pgbuf; + lock_kernel(); err = video_exclusive_open(inode,file); - if (err < 0) + if (err < 0) { + unlock_kernel(); return err; + } if (t->client==NULL) { err = -ENODEV; @@ -665,10 +669,12 @@ static int saa5249_open(struct inode *inode, struct file *file) t->is_searching[pgbuf] = false; } t->virtual_mode = false; + unlock_kernel(); return 0; fail: video_exclusive_release(inode,file); + unlock_kernel(); return err; } @@ -712,9 +718,7 @@ static const struct file_operations saa_fops = { static struct video_device saa_template = { - .owner = THIS_MODULE, .name = IF_NAME, - .type = VID_TYPE_TELETEXT, /*| VID_TYPE_TUNER ?? */ .fops = &saa_fops, }; diff --git a/linux/drivers/media/video/saa7134/Kconfig b/linux/drivers/media/video/saa7134/Kconfig index 83f076abc..7021bbf58 100644 --- a/linux/drivers/media/video/saa7134/Kconfig +++ b/linux/drivers/media/video/saa7134/Kconfig @@ -27,9 +27,7 @@ config VIDEO_SAA7134_ALSA config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" depends on VIDEO_SAA7134 && DVB_CORE - depends on HOTPLUG # due to FW_LOADER select VIDEOBUF_DVB - select FW_LOADER select DVB_PLL if !DVB_FE_CUSTOMISE select DVB_MT352 if !DVB_FE_CUSTOMISE select DVB_TDA1004X if !DVB_FE_CUSTOMISE diff --git a/linux/drivers/media/video/saa7134/saa6752hs.c b/linux/drivers/media/video/saa7134/saa6752hs.c index c5c19a2e3..011fc19f6 100644 --- a/linux/drivers/media/video/saa7134/saa6752hs.c +++ b/linux/drivers/media/video/saa7134/saa6752hs.c @@ -1,3 +1,27 @@ + /* + saa6752hs - i2c-driver for the saa6752hs by Philips + + Copyright (C) 2004 Andrew de Quincey + + AC-3 support: + + Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License vs 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 Mvss Ave, Cambridge, MA 02139, USA. + */ + #include <linux/module.h> #include <linux/kernel.h> #include <linux/string.h> @@ -11,6 +35,8 @@ #include "compat.h" #include <linux/videodev2.h> #include <media/v4l2-common.h> +#include <media/v4l2-chip-ident.h> +#include <media/v4l2-i2c-drv-legacy.h> #include <linux/init.h> #include <linux/crc32.h> @@ -28,9 +54,6 @@ MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder"); MODULE_AUTHOR("Andrew de Quincey"); MODULE_LICENSE("GPL"); -static struct i2c_driver driver; -static struct i2c_client client_template; - enum saa6752hs_videoformat { SAA6752HS_VF_D1 = 0, /* standard D1 video format: 720x576 */ SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */ @@ -47,7 +70,9 @@ struct saa6752hs_mpeg_params { __u16 ts_pid_pcr; /* audio */ - enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate; + enum v4l2_mpeg_audio_encoding au_encoding; + enum v4l2_mpeg_audio_l2_bitrate au_l2_bitrate; + enum v4l2_mpeg_audio_ac3_bitrate au_ac3_bitrate; /* video */ enum v4l2_mpeg_video_aspect vi_aspect; @@ -71,7 +96,9 @@ static const struct v4l2_format v4l2_format_table[] = }; struct saa6752hs_state { - struct i2c_client client; + int chip; + u32 revision; + int has_ac3; struct saa6752hs_mpeg_params params; enum saa6752hs_videoformat video_format; v4l2_std_id standard; @@ -146,6 +173,39 @@ static u8 PMT[] = { 0x00, 0x00, 0x00, 0x00 /* CRC32 */ }; +static u8 PMT_AC3[] = { + 0xc2, /* i2c register */ + 0x01, /* table number for encoder(1) */ + 0x47, /* sync */ + + 0x40, /* transport_error_indicator(0), payload_unit_start(1), transport_priority(0) */ + 0x10, /* PMT PID (0x0010) */ + 0x10, /* transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) */ + + 0x00, /* PSI pointer to start of table */ + + 0x02, /* TID (2) */ + 0xb0, 0x1a, /* section_syntax_indicator(1), section_length(26) */ + + 0x00, 0x01, /* program_number(1) */ + + 0xc1, /* version_number(0), current_next_indicator(1) */ + + 0x00, 0x00, /* section_number(0), last_section_number(0) */ + + 0xe1, 0x04, /* PCR_PID (0x0104) */ + + 0xf0, 0x00, /* program_info_length(0) */ + + 0x02, 0xe1, 0x00, 0xf0, 0x00, /* video stream type(2), pid */ + 0x06, 0xe1, 0x03, 0xf0, 0x03, /* audio stream type(6), pid */ + 0x6a, /* AC3 */ + 0x01, /* Descriptor_length(1) */ + 0x00, /* component_type_flag(0), bsid_flag(0), mainid_flag(0), asvc_flag(0), reserved flags(0) */ + + 0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */ +}; + static struct saa6752hs_mpeg_params param_defaults = { .ts_pid_pmt = 16, @@ -158,7 +218,9 @@ static struct saa6752hs_mpeg_params param_defaults = .vi_bitrate_peak = 6000, .vi_bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_VBR, + .au_encoding = V4L2_MPEG_AUDIO_ENCODING_LAYER_2, .au_l2_bitrate = V4L2_MPEG_AUDIO_L2_BITRATE_256K, + .au_ac3_bitrate = V4L2_MPEG_AUDIO_AC3_BITRATE_256K, }; /* ---------------------------------------------------------------------- */ @@ -231,8 +293,9 @@ static int saa6752hs_chip_command(struct i2c_client* client, static int saa6752hs_set_bitrate(struct i2c_client* client, - struct saa6752hs_mpeg_params* params) + struct saa6752hs_state *h) { + struct saa6752hs_mpeg_params *params = &h->params; u8 buf[3]; int tot_bitrate; @@ -264,11 +327,19 @@ static int saa6752hs_set_bitrate(struct i2c_client* client, tot_bitrate = params->vi_bitrate; } + /* set the audio encoding */ + buf[0] = 0x93; + buf[1] = (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3); + i2c_master_send(client, buf, 2); + /* set the audio bitrate */ buf[0] = 0x94; - buf[1] = (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 0 : 1; + if (params->au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) + buf[1] = V4L2_MPEG_AUDIO_AC3_BITRATE_384K == params->au_ac3_bitrate; + else + buf[1] = V4L2_MPEG_AUDIO_L2_BITRATE_384K == params->au_l2_bitrate; + tot_bitrate += buf[1] ? 384 : 256; i2c_master_send(client, buf, 2); - tot_bitrate += (V4L2_MPEG_AUDIO_L2_BITRATE_256K == params->au_l2_bitrate) ? 256 : 384; /* Note: the total max bitrate is determined by adding the video and audio bitrates together and also adding an extra 768kbit/s to stay on the @@ -333,7 +404,7 @@ static void saa6752hs_set_subsampling(struct i2c_client* client, } -static int handle_ctrl(struct saa6752hs_mpeg_params *params, +static int handle_ctrl(int has_ac3, struct saa6752hs_mpeg_params *params, struct v4l2_ext_control *ctrl, unsigned int cmd) { int old = 0, new; @@ -380,8 +451,9 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params, params->ts_pid_pcr = new; break; case V4L2_CID_MPEG_AUDIO_ENCODING: - old = V4L2_MPEG_AUDIO_ENCODING_LAYER_2; - if (set && new != old) + old = params->au_encoding; + if (set && new != V4L2_MPEG_AUDIO_ENCODING_LAYER_2 && + (!has_ac3 || new != V4L2_MPEG_AUDIO_ENCODING_AC3)) return -ERANGE; new = old; break; @@ -396,6 +468,19 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params, new = V4L2_MPEG_AUDIO_L2_BITRATE_384K; params->au_l2_bitrate = new; break; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + if (!has_ac3) + return -EINVAL; + old = params->au_ac3_bitrate; + if (set && new != V4L2_MPEG_AUDIO_AC3_BITRATE_256K && + new != V4L2_MPEG_AUDIO_AC3_BITRATE_384K) + return -ERANGE; + if (new <= V4L2_MPEG_AUDIO_AC3_BITRATE_256K) + new = V4L2_MPEG_AUDIO_AC3_BITRATE_256K; + else + new = V4L2_MPEG_AUDIO_AC3_BITRATE_384K; + params->au_ac3_bitrate = new; + break; case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: old = V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000; if (set && new != old) @@ -449,17 +534,19 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params, return 0; } -static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params, +static int saa6752hs_qctrl(struct saa6752hs_state *h, struct v4l2_queryctrl *qctrl) { + struct saa6752hs_mpeg_params *params = &h->params; int err; switch (qctrl->id) { case V4L2_CID_MPEG_AUDIO_ENCODING: return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_AUDIO_ENCODING_LAYER_2, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1, - V4L2_MPEG_AUDIO_ENCODING_LAYER_2); + h->has_ac3 ? V4L2_MPEG_AUDIO_ENCODING_AC3 : + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + 1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2); case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return v4l2_ctrl_query_fill(qctrl, @@ -467,6 +554,14 @@ static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params, V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1, V4L2_MPEG_AUDIO_L2_BITRATE_256K); + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + if (!h->has_ac3) + return -EINVAL; + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_AC3_BITRATE_256K, + V4L2_MPEG_AUDIO_AC3_BITRATE_384K, 1, + V4L2_MPEG_AUDIO_AC3_BITRATE_256K); + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, @@ -513,44 +608,57 @@ static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params, return -EINVAL; } -static int saa6752hs_qmenu(struct saa6752hs_mpeg_params *params, +static int saa6752hs_qmenu(struct saa6752hs_state *h, struct v4l2_querymenu *qmenu) { - static const char *mpeg_audio_l2_bitrate[] = { - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "", - "256 kbps", - "", - "384 kbps", - NULL + static const u32 mpeg_audio_encoding[] = { + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + V4L2_CTRL_MENU_IDS_END + }; + static const u32 mpeg_audio_ac3_encoding[] = { + V4L2_MPEG_AUDIO_ENCODING_LAYER_2, + V4L2_MPEG_AUDIO_ENCODING_AC3, + V4L2_CTRL_MENU_IDS_END + }; + static u32 mpeg_audio_l2_bitrate[] = { + V4L2_MPEG_AUDIO_L2_BITRATE_256K, + V4L2_MPEG_AUDIO_L2_BITRATE_384K, + V4L2_CTRL_MENU_IDS_END + }; + static u32 mpeg_audio_ac3_bitrate[] = { + V4L2_MPEG_AUDIO_AC3_BITRATE_256K, + V4L2_MPEG_AUDIO_AC3_BITRATE_384K, + V4L2_CTRL_MENU_IDS_END }; struct v4l2_queryctrl qctrl; int err; qctrl.id = qmenu->id; - err = saa6752hs_qctrl(params, &qctrl); + err = saa6752hs_qctrl(h, &qctrl); if (err) return err; - if (qmenu->id == V4L2_CID_MPEG_AUDIO_L2_BITRATE) - return v4l2_ctrl_query_menu(qmenu, &qctrl, + switch (qmenu->id) { + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: + return v4l2_ctrl_query_menu_valid_items(qmenu, mpeg_audio_l2_bitrate); - return v4l2_ctrl_query_menu(qmenu, &qctrl, - v4l2_ctrl_get_menu(qmenu->id)); + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + if (!h->has_ac3) + return -EINVAL; + return v4l2_ctrl_query_menu_valid_items(qmenu, + mpeg_audio_ac3_bitrate); + case V4L2_CID_MPEG_AUDIO_ENCODING: + return v4l2_ctrl_query_menu_valid_items(qmenu, + h->has_ac3 ? mpeg_audio_ac3_encoding : + mpeg_audio_encoding); + } + return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL); } static int saa6752hs_init(struct i2c_client* client) { unsigned char buf[9], buf2[4]; struct saa6752hs_state *h; + unsigned size; u32 crc; unsigned char localPAT[256]; unsigned char localPMT[256]; @@ -570,7 +678,7 @@ static int saa6752hs_init(struct i2c_client* client) i2c_master_send(client, buf, 2); /* set bitrate */ - saa6752hs_set_bitrate(client, &h->params); + saa6752hs_set_bitrate(client, h); /* Set GOP structure {3, 13} */ buf[0] = 0x72; @@ -609,7 +717,13 @@ static int saa6752hs_init(struct i2c_client* client) localPAT[sizeof(PAT) - 1] = crc & 0xFF; /* compute PMT */ - memcpy(localPMT, PMT, sizeof(PMT)); + if (h->params.au_encoding == V4L2_MPEG_AUDIO_ENCODING_AC3) { + size = sizeof(PMT_AC3); + memcpy(localPMT, PMT_AC3, size); + } else { + size = sizeof(PMT); + memcpy(localPMT, PMT, size); + } localPMT[3] = 0x40 | ((h->params.ts_pid_pmt >> 8) & 0x0f); localPMT[4] = h->params.ts_pid_pmt & 0xff; localPMT[15] = 0xE0 | ((h->params.ts_pid_pcr >> 8) & 0x0F); @@ -618,11 +732,11 @@ static int saa6752hs_init(struct i2c_client* client) localPMT[21] = h->params.ts_pid_video & 0xFF; localPMT[25] = 0xE0 | ((h->params.ts_pid_audio >> 8) & 0x0F); localPMT[26] = h->params.ts_pid_audio & 0xFF; - crc = crc32_be(~0, &localPMT[7], sizeof(PMT) - 7 - 4); - localPMT[sizeof(PMT) - 4] = (crc >> 24) & 0xFF; - localPMT[sizeof(PMT) - 3] = (crc >> 16) & 0xFF; - localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF; - localPMT[sizeof(PMT) - 1] = crc & 0xFF; + crc = crc32_be(~0, &localPMT[7], size - 7 - 4); + localPMT[size - 4] = (crc >> 24) & 0xFF; + localPMT[size - 3] = (crc >> 16) & 0xFF; + localPMT[size - 2] = (crc >> 8) & 0xFF; + localPMT[size - 1] = crc & 0xFF; /* Set Audio PID */ buf[0] = 0xC1; @@ -643,8 +757,8 @@ static int saa6752hs_init(struct i2c_client* client) i2c_master_send(client,buf,3); /* Send SI tables */ - i2c_master_send(client,localPAT,sizeof(PAT)); - i2c_master_send(client,localPMT,sizeof(PMT)); + i2c_master_send(client, localPAT, sizeof(PAT)); + i2c_master_send(client, localPMT, size); /* mute then unmute audio. This removes buzzing artefacts */ buf[0] = 0xa4; @@ -689,45 +803,6 @@ static int saa6752hs_init(struct i2c_client* client) return 0; } -static int saa6752hs_attach(struct i2c_adapter *adap, int addr, int kind) -{ - struct saa6752hs_state *h; - - - if (NULL == (h = kzalloc(sizeof(*h), GFP_KERNEL))) - return -ENOMEM; - h->client = client_template; - h->params = param_defaults; - h->client.adapter = adap; - h->client.addr = addr; - - /* Assume 625 input lines */ - h->standard = 0; - - i2c_set_clientdata(&h->client, h); - i2c_attach_client(&h->client); - - v4l_info(&h->client,"saa6752hs: chip found @ 0x%x\n", addr<<1); - return 0; -} - -static int saa6752hs_probe(struct i2c_adapter *adap) -{ - if (adap->class & I2C_CLASS_TV_ANALOG) - return i2c_probe(adap, &addr_data, saa6752hs_attach); - return 0; -} - -static int saa6752hs_detach(struct i2c_client *client) -{ - struct saa6752hs_state *h; - - h = i2c_get_clientdata(client); - i2c_detach_client(client); - kfree(h); - return 0; -} - static int saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) { @@ -753,7 +828,8 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) return -EINVAL; params = h->params; for (i = 0; i < ctrls->count; i++) { - if ((err = handle_ctrl(¶ms, ctrls->controls + i, cmd))) { + err = handle_ctrl(h->has_ac3, ¶ms, ctrls->controls + i, cmd); + if (err) { ctrls->error_idx = i; return err; } @@ -761,9 +837,9 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) h->params = params; break; case VIDIOC_QUERYCTRL: - return saa6752hs_qctrl(&h->params, arg); + return saa6752hs_qctrl(h, arg); case VIDIOC_QUERYMENU: - return saa6752hs_qmenu(&h->params, arg); + return saa6752hs_qmenu(h, arg); case VIDIOC_G_FMT: { struct v4l2_format *f = arg; @@ -786,6 +862,11 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) case VIDIOC_S_STD: h->standard = *((v4l2_std_id *) arg); break; + + case VIDIOC_G_CHIP_IDENT: + return v4l2_chip_ident_i2c_client(client, + arg, h->chip, h->revision); + default: /* nothing */ break; @@ -794,36 +875,59 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) return err; } -/* ----------------------------------------------------------------------- */ +static int saa6752hs_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct saa6752hs_state *h = kzalloc(sizeof(*h), GFP_KERNEL); + u8 addr = 0x13; + u8 data[12]; -static struct i2c_driver driver = { - .driver = { - .name = "saa6752hs", - }, - .id = I2C_DRIVERID_SAA6752HS, - .attach_adapter = saa6752hs_probe, - .detach_client = saa6752hs_detach, - .command = saa6752hs_command, -}; + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + if (h == NULL) + return -ENOMEM; -static struct i2c_client client_template = -{ - .name = "saa6752hs", - .driver = &driver, -}; + i2c_master_send(client, &addr, 1); + i2c_master_recv(client, data, sizeof(data)); + h->chip = V4L2_IDENT_SAA6752HS; + h->revision = (data[8] << 8) | data[9]; + h->has_ac3 = 0; + if (h->revision == 0x0206) { + h->chip = V4L2_IDENT_SAA6752HS_AC3; + h->has_ac3 = 1; + v4l_info(client, "support AC-3\n"); + } + h->params = param_defaults; + h->standard = 0; /* Assume 625 input lines */ -static int __init saa6752hs_init_module(void) -{ - return i2c_add_driver(&driver); + i2c_set_clientdata(client, h); + return 0; } -static void __exit saa6752hs_cleanup_module(void) +static int saa6752hs_remove(struct i2c_client *client) { - i2c_del_driver(&driver); + kfree(i2c_get_clientdata(client)); + return 0; } -module_init(saa6752hs_init_module); -module_exit(saa6752hs_cleanup_module); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) +static const struct i2c_device_id saa6752hs_id[] = { + { "saa6752hs", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, saa6752hs_id); + +#endif +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "saa6752hs", + .driverid = I2C_DRIVERID_SAA6752HS, + .command = saa6752hs_command, + .probe = saa6752hs_probe, + .remove = saa6752hs_remove, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) + .id_table = saa6752hs_id, +#endif +}; /* * Overrides for Emacs so that we follow Linus's tabbing style. diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c index 8ec09c97e..dfe4f7169 100644 --- a/linux/drivers/media/video/saa7134/saa7134-cards.c +++ b/linux/drivers/media/video/saa7134/saa7134-cards.c @@ -5956,9 +5956,6 @@ int saa7134_board_init2(struct saa7134_dev *dev) unsigned char buf; int board; - dev->tuner_type = saa7134_boards[dev->board].tuner_type; - dev->tuner_addr = saa7134_boards[dev->board].tuner_addr; - switch (dev->board) { case SAA7134_BOARD_BMK_MPEX_NOTUNER: case SAA7134_BOARD_BMK_MPEX_TUNER: diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c index 254a04717..62c9322aa 100644 --- a/linux/drivers/media/video/saa7134/saa7134-core.c +++ b/linux/drivers/media/video/saa7134/saa7134-core.c @@ -408,32 +408,6 @@ void saa7134_buffer_timeout(unsigned long data) spin_unlock_irqrestore(&dev->slock,flags); } -/* resends a current buffer in queue after resume */ - -static int saa7134_buffer_requeue(struct saa7134_dev *dev, - struct saa7134_dmaqueue *q) -{ - struct saa7134_buf *buf, *next; - - assert_spin_locked(&dev->slock); - - buf = q->curr; - next = buf; - dprintk("buffer_requeue\n"); - - if (!buf) - return 0; - - dprintk("buffer_requeue : resending active buffers \n"); - - if (!list_empty(&q->queue)) - next = list_entry(q->queue.next, struct saa7134_buf, - vb.queue); - buf->activate(dev, buf, next); - - return 0; -} - /* ------------------------------------------------------------------ */ int saa7134_set_dmabits(struct saa7134_dev *dev) @@ -1006,11 +980,12 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, dev->board = SAA7134_BOARD_UNKNOWN; } dev->autodetected = card[dev->nr] != dev->board; - dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tuner_addr = saa7134_boards[dev->board].tuner_addr; dev->tda9887_conf = saa7134_boards[dev->board].tda9887_conf; if (UNSET != tuner[dev->nr]) dev->tuner_type = tuner[dev->nr]; - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", dev->name,pci_dev->subsystem_vendor, pci_dev->subsystem_device,saa7134_boards[dev->board].name, dev->board, dev->autodetected ? @@ -1068,11 +1043,9 @@ 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("%s: Overlay support disabled.\n",dev->name); - } + if (saa7134_no_overlay > 0) + printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name); + dev->video_dev = vdev_init(dev,&saa7134_video_template,"video"); err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[dev->nr]); @@ -1085,7 +1058,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, dev->name,dev->video_dev->minor & 0x1f); dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi"); - dev->vbi_dev->type = VID_TYPE_TUNER | VID_TYPE_TELETEXT; err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, vbi_nr[dev->nr]); @@ -1205,6 +1177,32 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) } #ifdef CONFIG_PM + +/* resends a current buffer in queue after resume */ +static int saa7134_buffer_requeue(struct saa7134_dev *dev, + struct saa7134_dmaqueue *q) +{ + struct saa7134_buf *buf, *next; + + assert_spin_locked(&dev->slock); + + buf = q->curr; + next = buf; + dprintk("buffer_requeue\n"); + + if (!buf) + return 0; + + dprintk("buffer_requeue : resending active buffers \n"); + + if (!list_empty(&q->queue)) + next = list_entry(q->queue.next, struct saa7134_buf, + vb.queue); + buf->activate(dev, buf, next); + + return 0; +} + static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state) { diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c index dc3c2a6cb..5225ed6b8 100644 --- a/linux/drivers/media/video/saa7134/saa7134-empress.c +++ b/linux/drivers/media/video/saa7134/saa7134-empress.c @@ -29,6 +29,7 @@ #include <media/saa6752hs.h> #include <media/v4l2-common.h> +#include <media/v4l2-chip-ident.h> /* ------------------------------------------------------------------ */ @@ -79,9 +80,11 @@ static int ts_open(struct inode *inode, struct file *file) struct saa7134_dev *dev; int err; + lock_kernel(); list_for_each_entry(dev, &saa7134_devlist, devlist) if (dev->empress_dev && dev->empress_dev->minor == minor) goto found; + unlock_kernel(); return -ENODEV; found: @@ -89,20 +92,21 @@ static int ts_open(struct inode *inode, struct file *file) err = -EBUSY; if (!mutex_trylock(&dev->empress_tsq.vb_lock)) goto done; - if (dev->empress_users) + if (atomic_read(&dev->empress_users)) goto done_up; /* Unmute audio */ saa_writeb(SAA7134_AUDIO_MUTE_CTRL, saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6)); - dev->empress_users++; + atomic_inc(&dev->empress_users); file->private_data = dev; err = 0; done_up: mutex_unlock(&dev->empress_tsq.vb_lock); done: + unlock_kernel(); return err; } @@ -110,8 +114,6 @@ static int ts_release(struct inode *inode, struct file *file) { struct saa7134_dev *dev = file->private_data; - mutex_lock(&dev->empress_tsq.vb_lock); - videobuf_stop(&dev->empress_tsq); videobuf_mmap_free(&dev->empress_tsq); @@ -122,9 +124,7 @@ static int ts_release(struct inode *inode, struct file *file) saa_writeb(SAA7134_AUDIO_MUTE_CTRL, saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6)); - dev->empress_users--; - - mutex_unlock(&dev->empress_tsq.vb_lock); + atomic_dec(&dev->empress_users); return 0; } @@ -333,6 +333,22 @@ static int empress_g_ext_ctrls(struct file *file, void *priv, return saa7134_i2c_call_saa6752(dev, VIDIOC_G_EXT_CTRLS, ctrls); } +static int empress_g_ctrl(struct file *file, void *priv, + struct v4l2_control *c) +{ + struct saa7134_dev *dev = file->private_data; + + return saa7134_g_ctrl_internal(dev, NULL, c); +} + +static int empress_s_ctrl(struct file *file, void *priv, + struct v4l2_control *c) +{ + struct saa7134_dev *dev = file->private_data; + + return saa7134_s_ctrl_internal(dev, NULL, c); +} + static int empress_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c) { @@ -388,6 +404,25 @@ static int empress_querymenu(struct file *file, void *priv, return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c); } +static int empress_g_chip_ident(struct file *file, void *fh, + struct v4l2_chip_ident *chip) +{ + struct saa7134_dev *dev = file->private_data; + + chip->ident = V4L2_IDENT_NONE; + chip->revision = 0; + if (dev->mpeg_i2c_client == NULL) + return -EINVAL; + if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER && + chip->match_chip == I2C_DRIVERID_SAA6752HS) + return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip); + if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR && + chip->match_chip == dev->mpeg_i2c_client->addr) + return saa7134_i2c_call_saa6752(dev, VIDIOC_G_CHIP_IDENT, chip); + return -EINVAL; +} + + static const struct file_operations ts_fops = { .owner = THIS_MODULE, @@ -400,16 +435,7 @@ static const struct file_operations ts_fops = .llseek = no_llseek, }; -/* ----------------------------------------------------------- */ - -static struct video_device saa7134_empress_template = -{ - .name = "saa7134-empress", - .type = 0 /* FIXME */, - .type2 = 0 /* FIXME */, - .fops = &ts_fops, - .minor = -1, - +static const struct v4l2_ioctl_ops ts_ioctl_ops = { .vidioc_querycap = empress_querycap, .vidioc_enum_fmt_vid_cap = empress_enum_fmt_vid_cap, .vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap, @@ -425,11 +451,20 @@ static struct video_device saa7134_empress_template = .vidioc_enum_input = empress_enum_input, .vidioc_g_input = empress_g_input, .vidioc_s_input = empress_s_input, - .vidioc_queryctrl = empress_queryctrl, .vidioc_querymenu = empress_querymenu, - .vidioc_g_ctrl = saa7134_g_ctrl, - .vidioc_s_ctrl = saa7134_s_ctrl, + .vidioc_g_ctrl = empress_g_ctrl, + .vidioc_s_ctrl = empress_s_ctrl, + .vidioc_g_chip_ident = empress_g_chip_ident, +}; + +/* ----------------------------------------------------------- */ + +static struct video_device saa7134_empress_template = { + .name = "saa7134-empress", + .fops = &ts_fops, + .minor = -1, + .ioctl_ops = &ts_ioctl_ops, .tvnorms = SAA7134_NORMS, .current_norm = V4L2_STD_PAL, @@ -453,7 +488,7 @@ static void empress_signal_update(struct work_struct *work) ts_reset_encoder(dev); } else { dprintk("video signal acquired\n"); - if (dev->empress_users) + if (atomic_read(&dev->empress_users)) ts_init_encoder(dev); } } diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c index f26fd7061..a9f6df2dd 100644 --- a/linux/drivers/media/video/saa7134/saa7134-input.c +++ b/linux/drivers/media/video/saa7134/saa7134-input.c @@ -62,8 +62,11 @@ MODULE_PARM_DESC(disable_other_ir, "disable full codes of " #define i2cdprintk(fmt, arg...) if (ir_debug) \ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg) -/** rc5 functions */ +/* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */ static int saa7134_rc5_irq(struct saa7134_dev *dev); +static int saa7134_nec_irq(struct saa7134_dev *dev); +static void nec_task(unsigned long data); +static void saa7134_nec_timer(unsigned long data); /* -------------------- GPIO generic keycode builder -------------------- */ @@ -280,7 +283,9 @@ void saa7134_input_irq(struct saa7134_dev *dev) { struct card_ir *ir = dev->remote; - if (!ir->polling && !ir->rc5_gpio) { + if (ir->nec_gpio) { + saa7134_nec_irq(dev); + } else if (!ir->polling && !ir->rc5_gpio) { build_key(dev); } else if (ir->rc5_gpio) { saa7134_rc5_irq(dev); @@ -316,6 +321,10 @@ void saa7134_ir_start(struct saa7134_dev *dev, struct card_ir *ir) ir->addr = 0x17; ir->rc5_key_timeout = ir_rc5_key_timeout; ir->rc5_remote_gap = ir_rc5_remote_gap; + } else if (ir->nec_gpio) { + setup_timer(&ir->timer_keyup, saa7134_nec_timer, + (unsigned long)dev); + tasklet_init(&ir->tlet, nec_task, (unsigned long)dev); } } @@ -335,6 +344,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) u32 mask_keyup = 0; int polling = 0; int rc5_gpio = 0; + int nec_gpio = 0; int ir_type = IR_TYPE_OTHER; int err; @@ -533,6 +543,7 @@ int saa7134_input_init1(struct saa7134_dev *dev) ir->mask_keyup = mask_keyup; ir->polling = polling; ir->rc5_gpio = rc5_gpio; + ir->nec_gpio = nec_gpio; /* init input device */ snprintf(ir->name, sizeof(ir->name), "saa7134 IR (%s)", @@ -679,8 +690,129 @@ static int saa7134_rc5_irq(struct saa7134_dev *dev) return 1; } -/* ---------------------------------------------------------------------- - * Local variables: - * c-basic-offset: 8 - * End: + +/* On NEC protocol, One has 2.25 ms, and zero has 1.125 ms + The first pulse (start) has 9 + 4.5 ms */ + +static void saa7134_nec_timer(unsigned long data) +{ + struct saa7134_dev *dev = (struct saa7134_dev *) data; + struct card_ir *ir = dev->remote; + + dprintk("Cancel key repeat\n"); + + ir_input_nokey(ir->dev, &ir->ir); +} + +static void nec_task(unsigned long data) +{ + struct saa7134_dev *dev = (struct saa7134_dev *) data; + struct card_ir *ir; + struct timeval tv; + int count, pulse, oldpulse, gap; + u32 ircode = 0, not_code = 0; + int ngap = 0; + + if (!data) { + printk(KERN_ERR "saa713x/ir: Can't recover dev struct\n"); + /* GPIO will be kept disabled */ + return; + } + + ir = dev->remote; + + /* rising SAA7134_GPIO_GPRESCAN reads the status */ + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + + oldpulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown; + pulse = oldpulse; + + do_gettimeofday(&tv); + ir->base_time = tv; + + /* Decode NEC pulsecode. This code can take up to 76.5 ms to run. + Unfortunately, using IRQ to decode pulse didn't work, since it uses + a pulse train of 38KHz. This means one pulse on each 52 us + */ + do { + /* Wait until the end of pulse/space or 5 ms */ + for (count = 0; count < 500; count++) { + udelay(10); + /* rising SAA7134_GPIO_GPRESCAN reads the status */ + saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN); + pulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) + & ir->mask_keydown; + if (pulse != oldpulse) + break; + } + + do_gettimeofday(&tv); + gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) + + tv.tv_usec - ir->base_time.tv_usec; + + if (!pulse) { +#if 0 + if (!ngap && gap < 4000) + break; +#endif + /* Bit 0 has 560 us, while bit 1 has 1120 us. + Do something only if bit == 1 + */ + if (ngap && (gap > 560 + 280)) { + unsigned int shift = ngap - 1; + + /* Address first, then command */ + if (shift < 8) { + shift += 8; + ircode |= 1 << shift; + } else if (shift < 16) { + not_code |= 1 << shift; + } else if (shift < 24) { + shift -= 16; + ircode |= 1 << shift; + } else { + shift -= 24; + not_code |= 1 << shift; + } + } + ngap++; + } + + + ir->base_time = tv; + + /* TIMEOUT - Long pulse */ + if (gap >= 5000) + break; + oldpulse = pulse; + } while (ngap < 32); + + if (ngap == 32) { + /* FIXME: should check if not_code == ~ircode */ + ir->code = ir_extract_bits(ircode, ir->mask_keycode); + + dprintk("scancode = 0x%02x (code = 0x%02x, notcode= 0x%02x)\n", + ir->code, ircode, not_code); + + ir_input_keydown(ir->dev, &ir->ir, ir->code, ir->code); + } else + dprintk("Repeat last key\n"); + + /* Keep repeating the last key */ + mod_timer(&ir->timer_keyup, jiffies + msecs_to_jiffies(150)); + + saa_setl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18); +} + +static int saa7134_nec_irq(struct saa7134_dev *dev) +{ + struct card_ir *ir = dev->remote; + + saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18); + tasklet_schedule(&ir->tlet); + + return 1; +} diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c index e02bd2659..547c0401a 100644 --- a/linux/drivers/media/video/saa7134/saa7134-video.c +++ b/linux/drivers/media/video/saa7134/saa7134-video.c @@ -1112,10 +1112,8 @@ static struct videobuf_queue_ops video_qops = { /* ------------------------------------------------------------------ */ -int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) +int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) { - struct saa7134_fh *fh = priv; - struct saa7134_dev *dev = fh->dev; const struct v4l2_queryctrl* ctrl; ctrl = ctrl_by_id(c->id); @@ -1160,20 +1158,31 @@ int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) } return 0; } -EXPORT_SYMBOL_GPL(saa7134_g_ctrl); +EXPORT_SYMBOL_GPL(saa7134_g_ctrl_internal); -int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) +static int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c) +{ + struct saa7134_fh *fh = priv; + + return saa7134_g_ctrl_internal(fh->dev, fh, c); +} + +int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c) { const struct v4l2_queryctrl* ctrl; - struct saa7134_fh *fh = f; - struct saa7134_dev *dev = fh->dev; unsigned long flags; int restart_overlay = 0; - int err = -EINVAL; + int err; - err = v4l2_prio_check(&dev->prio, &fh->prio); - if (0 != err) - return err; + /* When called from the empress code fh == NULL. + That needs to be fixed somehow, but for now this is + good enough. */ + if (fh) { + err = v4l2_prio_check(&dev->prio, &fh->prio); + if (0 != err) + return err; + } + err = -EINVAL; mutex_lock(&dev->lock); @@ -1274,7 +1283,14 @@ error: mutex_unlock(&dev->lock); return err; } -EXPORT_SYMBOL_GPL(saa7134_s_ctrl); +EXPORT_SYMBOL_GPL(saa7134_s_ctrl_internal); + +static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c) +{ + struct saa7134_fh *fh = f; + + return saa7134_s_ctrl_internal(fh->dev, fh, c); +} /* ------------------------------------------------------------------ */ @@ -1314,6 +1330,8 @@ static int video_open(struct inode *inode, struct file *file) struct saa7134_fh *fh; enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; int radio = 0; + + lock_kernel(); list_for_each_entry(dev, &saa7134_devlist, devlist) { if (dev->video_dev && (dev->video_dev->minor == minor)) goto found; @@ -1326,6 +1344,7 @@ static int video_open(struct inode *inode, struct file *file) goto found; } } + unlock_kernel(); return -ENODEV; found: @@ -1334,8 +1353,10 @@ static int video_open(struct inode *inode, struct file *file) /* allocate + initialize per filehandle data */ fh = kzalloc(sizeof(*fh),GFP_KERNEL); - if (NULL == fh) + if (NULL == fh) { + unlock_kernel(); return -ENOMEM; + } file->private_data = fh; fh->dev = dev; fh->radio = radio; @@ -1368,6 +1389,7 @@ static int video_open(struct inode *inode, struct file *file) /* switch to video/vbi mode */ video_mux(dev,dev->ctl_input); } + unlock_kernel(); return 0; } @@ -2360,26 +2382,7 @@ static const struct file_operations video_fops = .llseek = no_llseek, }; -static const struct file_operations radio_fops = -{ - .owner = THIS_MODULE, - .open = video_open, - .release = video_release, - .ioctl = video_ioctl2, - .compat_ioctl = v4l_compat_ioctl32, - .llseek = no_llseek, -}; - -/* ----------------------------------------------------------- */ -/* exported stuff */ - -struct video_device saa7134_video_template = -{ - .name = "saa7134-video", - .type = VID_TYPE_CAPTURE|VID_TYPE_TUNER | - VID_TYPE_CLIPPING|VID_TYPE_SCALES, - .fops = &video_fops, - .minor = -1, +static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_querycap = saa7134_querycap, .vidioc_enum_fmt_vid_cap = saa7134_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = saa7134_g_fmt_vid_cap, @@ -2428,16 +2431,18 @@ struct video_device saa7134_video_template = .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif - .tvnorms = SAA7134_NORMS, - .current_norm = V4L2_STD_PAL, }; -struct video_device saa7134_radio_template = -{ - .name = "saa7134-radio", - .type = VID_TYPE_TUNER, - .fops = &radio_fops, - .minor = -1, +static const struct file_operations radio_fops = { + .owner = THIS_MODULE, + .open = video_open, + .release = video_release, + .ioctl = video_ioctl2, + .compat_ioctl = v4l_compat_ioctl32, + .llseek = no_llseek, +}; + +static const struct v4l2_ioctl_ops radio_ioctl_ops = { .vidioc_querycap = radio_querycap, .vidioc_g_tuner = radio_g_tuner, .vidioc_enum_input = radio_enum_input, @@ -2454,6 +2459,25 @@ struct video_device saa7134_radio_template = .vidioc_s_frequency = saa7134_s_frequency, }; +/* ----------------------------------------------------------- */ +/* exported stuff */ + +struct video_device saa7134_video_template = { + .name = "saa7134-video", + .fops = &video_fops, + .ioctl_ops = &video_ioctl_ops, + .minor = -1, + .tvnorms = SAA7134_NORMS, + .current_norm = V4L2_STD_PAL, +}; + +struct video_device saa7134_radio_template = { + .name = "saa7134-radio", + .fops = &radio_fops, + .ioctl_ops = &radio_ioctl_ops, + .minor = -1, +}; + int saa7134_video_init1(struct saa7134_dev *dev) { /* sanitycheck insmod options */ diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index 053c358ff..e3ad9d9e7 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -566,7 +566,7 @@ struct saa7134_dev { /* SAA7134_MPEG_EMPRESS only */ struct video_device *empress_dev; struct videobuf_queue empress_tsq; - unsigned int empress_users; + atomic_t empress_users; struct work_struct empress_workqueue; int empress_started; @@ -668,8 +668,8 @@ extern unsigned int video_debug; extern struct video_device saa7134_video_template; extern struct video_device saa7134_radio_template; -int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c); -int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c); +int saa7134_s_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); +int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c); int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c); int saa7134_videoport_init(struct saa7134_dev *dev); diff --git a/linux/drivers/media/video/saa717x.c b/linux/drivers/media/video/saa717x.c index a478bf25e..b0751c195 100644 --- a/linux/drivers/media/video/saa717x.c +++ b/linux/drivers/media/video/saa717x.c @@ -35,7 +35,6 @@ #include <linux/kernel.h> #include <linux/sched.h> -#include <linux/videodev.h> #include <linux/videodev2.h> #include <linux/i2c.h> #include <media/v4l2-common.h> diff --git a/linux/drivers/media/video/saa7196.h b/linux/drivers/media/video/saa7196.h deleted file mode 100644 index cd4b6354a..000000000 --- a/linux/drivers/media/video/saa7196.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - Definitions for the Philips SAA7196 digital video decoder, - scaler, and clock generator circuit (DESCpro), as used in - the PlanB video input of the Powermac 7x00/8x00 series. - - Copyright (C) 1998 Michel Lanners (mlan@cpu.lu) - - The register defines are shamelessly copied from the meteor - driver out of NetBSD (with permission), - and are copyrighted (c) 1995 Mark Tinguely and Jim Lowe - (Thanks !) - - Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu) - - The default values used for PlanB are my mistakes. -*/ - -/* $Id: saa7196.h,v 1.5 1999/03/26 23:28:47 mlan Exp $ */ - -#ifndef _SAA7196_H_ -#define _SAA7196_H_ - -#define SAA7196_NUMREGS 0x31 /* Number of registers (used)*/ -#define NUM_SUPPORTED_NORM 3 /* Number of supported norms by PlanB */ - -/* Decoder part: */ -#define SAA7196_IDEL 0x00 /* Increment delay */ -#define SAA7196_HSB5 0x01 /* H-sync begin; 50 hz */ -#define SAA7196_HSS5 0x02 /* H-sync stop; 50 hz */ -#define SAA7196_HCB5 0x03 /* H-clamp begin; 50 hz */ -#define SAA7196_HCS5 0x04 /* H-clamp stop; 50 hz */ -#define SAA7196_HSP5 0x05 /* H-sync after PHI1; 50 hz */ -#define SAA7196_LUMC 0x06 /* Luminance control */ -#define SAA7196_HUEC 0x07 /* Hue control */ -#define SAA7196_CKTQ 0x08 /* Colour Killer Threshold QAM (PAL, NTSC) */ -#define SAA7196_CKTS 0x09 /* Colour Killer Threshold SECAM */ -#define SAA7196_PALS 0x0a /* PAL switch sensitivity */ -#define SAA7196_SECAMS 0x0b /* SECAM switch sensitivity */ -#define SAA7196_CGAINC 0x0c /* Chroma gain control */ -#define SAA7196_STDC 0x0d /* Standard/Mode control */ -#define SAA7196_IOCC 0x0e /* I/O and Clock Control */ -#define SAA7196_CTRL1 0x0f /* Control #1 */ -#define SAA7196_CTRL2 0x10 /* Control #2 */ -#define SAA7196_CGAINR 0x11 /* Chroma Gain Reference */ -#define SAA7196_CSAT 0x12 /* Chroma Saturation */ -#define SAA7196_CONT 0x13 /* Luminance Contrast */ -#define SAA7196_HSB6 0x14 /* H-sync begin; 60 hz */ -#define SAA7196_HSS6 0x15 /* H-sync stop; 60 hz */ -#define SAA7196_HCB6 0x16 /* H-clamp begin; 60 hz */ -#define SAA7196_HCS6 0x17 /* H-clamp stop; 60 hz */ -#define SAA7196_HSP6 0x18 /* H-sync after PHI1; 60 hz */ -#define SAA7196_BRIG 0x19 /* Luminance Brightness */ - -/* Scaler part: */ -#define SAA7196_FMTS 0x20 /* Formats and sequence */ -#define SAA7196_OUTPIX 0x21 /* Output data pixel/line */ -#define SAA7196_INPIX 0x22 /* Input data pixel/line */ -#define SAA7196_HWS 0x23 /* Horiz. window start */ -#define SAA7196_HFILT 0x24 /* Horiz. filter */ -#define SAA7196_OUTLINE 0x25 /* Output data lines/field */ -#define SAA7196_INLINE 0x26 /* Input data lines/field */ -#define SAA7196_VWS 0x27 /* Vertical window start */ -#define SAA7196_VYP 0x28 /* AFS/vertical Y processing */ -#define SAA7196_VBS 0x29 /* Vertical Bypass start */ -#define SAA7196_VBCNT 0x2a /* Vertical Bypass count */ -#define SAA7196_VBP 0x2b /* veritcal Bypass Polarity */ -#define SAA7196_VLOW 0x2c /* Colour-keying lower V limit */ -#define SAA7196_VHIGH 0x2d /* Colour-keying upper V limit */ -#define SAA7196_ULOW 0x2e /* Colour-keying lower U limit */ -#define SAA7196_UHIGH 0x2f /* Colour-keying upper U limit */ -#define SAA7196_DPATH 0x30 /* Data path setting */ - -/* Initialization default values: */ - -unsigned char saa_regs[NUM_SUPPORTED_NORM][SAA7196_NUMREGS] = { - -/* PAL, 768x576 (no scaling), composite video-in */ -/* Decoder: */ - { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff, - 0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x06, 0x3b, 0x98, - 0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2, - 0xe9, 0xa2, -/* Padding */ - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* Scaler: */ - 0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12, - 0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, - 0x87 }, - -/* NTSC, 640x480? (no scaling), composite video-in */ -/* Decoder: */ - { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x50, 0x00, - 0xf8, 0xf0, 0xfe, 0xe0, 0x00, 0x06, 0x3b, 0x98, - 0x00, 0x2c, 0x3d, 0x40, 0x34, 0x0a, 0xf4, 0xd2, - 0xe9, 0x98, -/* Padding */ - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* Scaler: */ - 0x72, 0x80, 0x80, 0x03, 0x89, 0xf0, 0xf0, 0x0d, - 0xa0, 0x0d, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, - 0x87 }, - -/* SECAM, 768x576 (no scaling), composite video-in */ -/* Decoder: */ - { 0x50, 0x30, 0x00, 0xe8, 0xb6, 0xe5, 0x63, 0xff, - 0xfe, 0xf0, 0xfe, 0xe0, 0x20, 0x07, 0x3b, 0x98, - 0x00, 0x59, 0x41, 0x45, 0x34, 0x0a, 0xf4, 0xd2, - 0xe9, 0xa2, -/* Padding */ - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, -/* Scaler: */ - 0x72, 0x80, 0x00, 0x03, 0x8d, 0x20, 0x20, 0x12, - 0xa5, 0x12, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, - 0x87 } - }; - -#endif /* _SAA7196_H_ */ diff --git a/linux/drivers/media/video/se401.c b/linux/drivers/media/video/se401.c index c82bfddde..04897413d 100644 --- a/linux/drivers/media/video/se401.c +++ b/linux/drivers/media/video/se401.c @@ -944,14 +944,18 @@ static int se401_open(struct inode *inode, struct file *file) struct usb_se401 *se401 = (struct usb_se401 *)dev; int err = 0; - if (se401->user) + lock_kernel(); + if (se401->user) { + unlock_kernel(); return -EBUSY; + } se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES); if (se401->fbuf) file->private_data = dev; else err = -ENOMEM; se401->user = !err; + unlock_kernel(); return err; } @@ -1238,9 +1242,7 @@ static const struct file_operations se401_fops = { .llseek = no_llseek, }; static struct video_device se401_template = { - .owner = THIS_MODULE, .name = "se401 USB camera", - .type = VID_TYPE_CAPTURE, .fops = &se401_fops, }; diff --git a/linux/drivers/media/video/sh_mobile_ceu_camera.c b/linux/drivers/media/video/sh_mobile_ceu_camera.c index f7ca3cb93..76838091d 100644 --- a/linux/drivers/media/video/sh_mobile_ceu_camera.c +++ b/linux/drivers/media/video/sh_mobile_ceu_camera.c @@ -304,9 +304,6 @@ static int sh_mobile_ceu_add_device(struct soc_camera_device *icd) "SuperH Mobile CEU driver attached to camera %d\n", icd->devnum); - if (pcdev->pdata->enable_camera) - pcdev->pdata->enable_camera(); - ret = icd->ops->init(icd); if (ret) goto err; @@ -333,8 +330,6 @@ static void sh_mobile_ceu_remove_device(struct soc_camera_device *icd) ceu_write(pcdev, CEIER, 0); ceu_write(pcdev, CAPSR, 1 << 16); /* reset */ icd->ops->release(icd); - if (pcdev->pdata->disable_camera) - pcdev->pdata->disable_camera(); dev_info(&icd->dev, "SuperH Mobile CEU driver detached from camera %d\n", @@ -647,7 +642,7 @@ static int __init sh_mobile_ceu_init(void) static void __exit sh_mobile_ceu_exit(void) { - return platform_driver_unregister(&sh_mobile_ceu_driver); + platform_driver_unregister(&sh_mobile_ceu_driver); } module_init(sh_mobile_ceu_init); diff --git a/linux/drivers/media/video/sn9c102/sn9c102_core.c b/linux/drivers/media/video/sn9c102/sn9c102_core.c index ea062da55..e92e79da3 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_core.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_core.c @@ -3313,8 +3313,6 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, "SN9C1xx PC Camera"); - cam->v4ldev->owner = THIS_MODULE; - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &sn9c102_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; diff --git a/linux/drivers/media/video/soc_camera.c b/linux/drivers/media/video/soc_camera.c index b01749088..66ebe5956 100644 --- a/linux/drivers/media/video/soc_camera.c +++ b/linux/drivers/media/video/soc_camera.c @@ -732,10 +732,36 @@ static int soc_camera_remove(struct device *dev) return 0; } +static int soc_camera_suspend(struct device *dev, pm_message_t state) +{ + struct soc_camera_device *icd = to_soc_camera_dev(dev); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + int ret = 0; + + if (ici->ops->suspend) + ret = ici->ops->suspend(icd, state); + + return ret; +} + +static int soc_camera_resume(struct device *dev) +{ + struct soc_camera_device *icd = to_soc_camera_dev(dev); + struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); + int ret = 0; + + if (ici->ops->resume) + ret = ici->ops->resume(icd); + + return ret; +} + static struct bus_type soc_camera_bus_type = { .name = "soc-camera", .probe = soc_camera_probe, .remove = soc_camera_remove, + .suspend = soc_camera_suspend, + .resume = soc_camera_resume, }; static struct device_driver ic_drv = { @@ -862,6 +888,35 @@ void soc_camera_device_unregister(struct soc_camera_device *icd) } EXPORT_SYMBOL(soc_camera_device_unregister); +static const struct v4l2_ioctl_ops soc_camera_ioctl_ops = { + .vidioc_querycap = soc_camera_querycap, + .vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap, + .vidioc_enum_input = soc_camera_enum_input, + .vidioc_g_input = soc_camera_g_input, + .vidioc_s_input = soc_camera_s_input, + .vidioc_s_std = soc_camera_s_std, + .vidioc_reqbufs = soc_camera_reqbufs, + .vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap, + .vidioc_querybuf = soc_camera_querybuf, + .vidioc_qbuf = soc_camera_qbuf, + .vidioc_dqbuf = soc_camera_dqbuf, + .vidioc_streamon = soc_camera_streamon, + .vidioc_streamoff = soc_camera_streamoff, + .vidioc_queryctrl = soc_camera_queryctrl, + .vidioc_g_ctrl = soc_camera_g_ctrl, + .vidioc_s_ctrl = soc_camera_s_ctrl, + .vidioc_cropcap = soc_camera_cropcap, + .vidioc_g_crop = soc_camera_g_crop, + .vidioc_s_crop = soc_camera_s_crop, + .vidioc_g_chip_ident = soc_camera_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = soc_camera_g_register, + .vidioc_s_register = soc_camera_s_register, +#endif +}; + int soc_camera_video_start(struct soc_camera_device *icd) { struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent); @@ -879,38 +934,12 @@ int soc_camera_video_start(struct soc_camera_device *icd) strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name)); /* Maybe better &ici->dev */ vdev->parent = &icd->dev; - vdev->type = VID_TYPE_CAPTURE; vdev->current_norm = V4L2_STD_UNKNOWN; vdev->fops = &soc_camera_fops; + vdev->ioctl_ops = &soc_camera_ioctl_ops; vdev->release = video_device_release; vdev->minor = -1; vdev->tvnorms = V4L2_STD_UNKNOWN, - vdev->vidioc_querycap = soc_camera_querycap; - vdev->vidioc_g_fmt_vid_cap = soc_camera_g_fmt_vid_cap; - vdev->vidioc_enum_fmt_vid_cap = soc_camera_enum_fmt_vid_cap; - vdev->vidioc_s_fmt_vid_cap = soc_camera_s_fmt_vid_cap; - vdev->vidioc_enum_input = soc_camera_enum_input; - vdev->vidioc_g_input = soc_camera_g_input; - vdev->vidioc_s_input = soc_camera_s_input; - vdev->vidioc_s_std = soc_camera_s_std; - vdev->vidioc_reqbufs = soc_camera_reqbufs; - vdev->vidioc_try_fmt_vid_cap = soc_camera_try_fmt_vid_cap; - vdev->vidioc_querybuf = soc_camera_querybuf; - vdev->vidioc_qbuf = soc_camera_qbuf; - vdev->vidioc_dqbuf = soc_camera_dqbuf; - vdev->vidioc_streamon = soc_camera_streamon; - vdev->vidioc_streamoff = soc_camera_streamoff; - vdev->vidioc_queryctrl = soc_camera_queryctrl; - vdev->vidioc_g_ctrl = soc_camera_g_ctrl; - vdev->vidioc_s_ctrl = soc_camera_s_ctrl; - vdev->vidioc_cropcap = soc_camera_cropcap; - vdev->vidioc_g_crop = soc_camera_g_crop; - vdev->vidioc_s_crop = soc_camera_s_crop; - vdev->vidioc_g_chip_ident = soc_camera_g_chip_ident; -#ifdef CONFIG_VIDEO_ADV_DEBUG - vdev->vidioc_g_register = soc_camera_g_register; - vdev->vidioc_s_register = soc_camera_s_register; -#endif icd->current_fmt = &icd->formats[0]; diff --git a/linux/drivers/media/video/soc_camera_platform.c b/linux/drivers/media/video/soc_camera_platform.c index eefb0327e..1adc257eb 100644 --- a/linux/drivers/media/video/soc_camera_platform.c +++ b/linux/drivers/media/video/soc_camera_platform.c @@ -187,7 +187,7 @@ static int __init soc_camera_platform_module_init(void) static void __exit soc_camera_platform_module_exit(void) { - return platform_driver_unregister(&soc_camera_platform_driver); + platform_driver_unregister(&soc_camera_platform_driver); } module_init(soc_camera_platform_module_init); diff --git a/linux/drivers/media/video/stk-webcam.c b/linux/drivers/media/video/stk-webcam.c index 0c605632b..c6660b363 100644 --- a/linux/drivers/media/video/stk-webcam.c +++ b/linux/drivers/media/video/stk-webcam.c @@ -342,17 +342,19 @@ static int stk_create_sysfs_files(struct video_device *vdev) { int ret; - ret = video_device_create_file(vdev, &dev_attr_brightness); - ret += video_device_create_file(vdev, &dev_attr_hflip); - ret += video_device_create_file(vdev, &dev_attr_vflip); + ret = device_create_file(&vdev->dev, &dev_attr_brightness); + ret += device_create_file(&vdev->dev, &dev_attr_hflip); + ret += device_create_file(&vdev->dev, &dev_attr_vflip); + if (ret) + STK_WARNING("Could not create sysfs files\n"); return ret; } static void stk_remove_sysfs_files(struct video_device *vdev) { - video_device_remove_file(vdev, &dev_attr_brightness); - video_device_remove_file(vdev, &dev_attr_hflip); - video_device_remove_file(vdev, &dev_attr_vflip); + device_remove_file(&vdev->dev, &dev_attr_brightness); + device_remove_file(&vdev->dev, &dev_attr_hflip); + device_remove_file(&vdev->dev, &dev_attr_vflip); } #else @@ -444,18 +446,19 @@ static void stk_isoc_handler(struct urb *urb) fb->v4lbuf.bytesused = 0; fill = fb->buffer; } else if (fb->v4lbuf.bytesused == dev->frame_size) { - list_move_tail(dev->sio_avail.next, - &dev->sio_full); - wake_up(&dev->wait_frame); - if (list_empty(&dev->sio_avail)) { - (void) (printk_ratelimit() && - STK_ERROR("No buffer available\n")); - goto resubmit; + if (list_is_singular(&dev->sio_avail)) { + /* Always reuse the last buffer */ + fb->v4lbuf.bytesused = 0; + fill = fb->buffer; + } else { + list_move_tail(dev->sio_avail.next, + &dev->sio_full); + wake_up(&dev->wait_frame); + fb = list_first_entry(&dev->sio_avail, + struct stk_sio_buffer, list); + fb->v4lbuf.bytesused = 0; + fill = fb->buffer; } - fb = list_first_entry(&dev->sio_avail, - struct stk_sio_buffer, list); - fb->v4lbuf.bytesused = 0; - fill = fb->buffer; } } else { framelen -= 4; @@ -687,11 +690,15 @@ static int v4l_stk_open(struct inode *inode, struct file *fp) vdev = video_devdata(fp); dev = vdev_to_camera(vdev); - if (dev == NULL || !is_present(dev)) + lock_kernel(); + if (dev == NULL || !is_present(dev)) { + unlock_kernel(); return -ENXIO; + } fp->private_data = vdev; kref_get(&dev->kref); usb_autopm_get_interface(dev->interface); + unlock_kernel(); return 0; } @@ -1329,20 +1336,7 @@ static struct file_operations v4l_stk_fops = { .llseek = no_llseek }; -static void stk_v4l_dev_release(struct video_device *vd) -{ -} - -static struct video_device stk_v4l_data = { - .name = "stkwebcam", - .type = VFL_TYPE_GRABBER, - .type2 = VID_TYPE_CAPTURE, - .minor = -1, - .tvnorms = V4L2_STD_UNKNOWN, - .current_norm = V4L2_STD_UNKNOWN, - .fops = &v4l_stk_fops, - .release = stk_v4l_dev_release, - +static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = { .vidioc_querycap = stk_vidioc_querycap, .vidioc_enum_fmt_vid_cap = stk_vidioc_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap = stk_vidioc_try_fmt_vid_cap, @@ -1364,6 +1358,20 @@ static struct video_device stk_v4l_data = { .vidioc_g_parm = stk_vidioc_g_parm, }; +static void stk_v4l_dev_release(struct video_device *vd) +{ +} + +static struct video_device stk_v4l_data = { + .name = "stkwebcam", + .minor = -1, + .tvnorms = V4L2_STD_UNKNOWN, + .current_norm = V4L2_STD_UNKNOWN, + .fops = &v4l_stk_fops, + .ioctl_ops = &v4l_stk_ioctl_ops, + .release = stk_v4l_dev_release, +}; + static int stk_register_video_device(struct stk_camera *dev) { diff --git a/linux/drivers/media/video/stradis.c b/linux/drivers/media/video/stradis.c index 7f46a1d64..a081307c7 100644 --- a/linux/drivers/media/video/stradis.c +++ b/linux/drivers/media/video/stradis.c @@ -1887,12 +1887,16 @@ static int saa_open(struct inode *inode, struct file *file) struct video_device *vdev = video_devdata(file); struct saa7146 *saa = container_of(vdev, struct saa7146, video_dev); + lock_kernel(); file->private_data = saa; saa->user++; - if (saa->user > 1) + if (saa->user > 1) { + unlock_kernel(); return 0; /* device open already, don't reset */ + } saa->writemode = VID_WRITE_MPEG_VID; /* default to video */ + unlock_kernel(); return 0; } @@ -1924,7 +1928,6 @@ static const struct file_operations saa_fops = { /* template for video_device-structure */ static struct video_device saa_template = { .name = "SAA7146A", - .type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY, .fops = &saa_fops, .minor = -1, }; diff --git a/linux/drivers/media/video/stv680.c b/linux/drivers/media/video/stv680.c index 29c62e534..de32a5266 100644 --- a/linux/drivers/media/video/stv680.c +++ b/linux/drivers/media/video/stv680.c @@ -526,53 +526,54 @@ static int stv680_create_sysfs_files(struct video_device *vdev) { int rc; - rc = video_device_create_file(vdev, &dev_attr_model); + rc = device_create_file(&vdev->dev, &dev_attr_model); if (rc) goto err; - rc = video_device_create_file(vdev, &dev_attr_in_use); + rc = device_create_file(&vdev->dev, &dev_attr_in_use); if (rc) goto err_model; - rc = video_device_create_file(vdev, &dev_attr_streaming); + rc = device_create_file(&vdev->dev, &dev_attr_streaming); if (rc) goto err_inuse; - rc = video_device_create_file(vdev, &dev_attr_palette); + rc = device_create_file(&vdev->dev, &dev_attr_palette); if (rc) goto err_stream; - rc = video_device_create_file(vdev, &dev_attr_frames_total); + rc = device_create_file(&vdev->dev, &dev_attr_frames_total); if (rc) goto err_pal; - rc = video_device_create_file(vdev, &dev_attr_frames_read); + rc = device_create_file(&vdev->dev, &dev_attr_frames_read); if (rc) goto err_framtot; - rc = video_device_create_file(vdev, &dev_attr_packets_dropped); + rc = device_create_file(&vdev->dev, &dev_attr_packets_dropped); if (rc) goto err_framread; - rc = video_device_create_file(vdev, &dev_attr_decoding_errors); + rc = device_create_file(&vdev->dev, &dev_attr_decoding_errors); if (rc) goto err_dropped; return 0; err_dropped: - video_device_remove_file(vdev, &dev_attr_packets_dropped); + device_remove_file(&vdev->dev, &dev_attr_packets_dropped); err_framread: - video_device_remove_file(vdev, &dev_attr_frames_read); + device_remove_file(&vdev->dev, &dev_attr_frames_read); err_framtot: - video_device_remove_file(vdev, &dev_attr_frames_total); + device_remove_file(&vdev->dev, &dev_attr_frames_total); err_pal: - video_device_remove_file(vdev, &dev_attr_palette); + device_remove_file(&vdev->dev, &dev_attr_palette); err_stream: - video_device_remove_file(vdev, &dev_attr_streaming); + device_remove_file(&vdev->dev, &dev_attr_streaming); err_inuse: - video_device_remove_file(vdev, &dev_attr_in_use); + device_remove_file(&vdev->dev, &dev_attr_in_use); err_model: - video_device_remove_file(vdev, &dev_attr_model); + device_remove_file(&vdev->dev, &dev_attr_model); err: + PDEBUG(0, "STV(e): Could not create sysfs files"); return rc; } static void stv680_remove_sysfs_files(struct video_device *vdev) { - video_device_remove_file(vdev, &dev_attr_model); - video_device_remove_file(vdev, &dev_attr_in_use); - video_device_remove_file(vdev, &dev_attr_streaming); - video_device_remove_file(vdev, &dev_attr_palette); - video_device_remove_file(vdev, &dev_attr_frames_total); - video_device_remove_file(vdev, &dev_attr_frames_read); - video_device_remove_file(vdev, &dev_attr_packets_dropped); - video_device_remove_file(vdev, &dev_attr_decoding_errors); + device_remove_file(&vdev->dev, &dev_attr_model); + device_remove_file(&vdev->dev, &dev_attr_in_use); + device_remove_file(&vdev->dev, &dev_attr_streaming); + device_remove_file(&vdev->dev, &dev_attr_palette); + device_remove_file(&vdev->dev, &dev_attr_frames_total); + device_remove_file(&vdev->dev, &dev_attr_frames_read); + device_remove_file(&vdev->dev, &dev_attr_packets_dropped); + device_remove_file(&vdev->dev, &dev_attr_decoding_errors); } /******************************************************************** @@ -1090,6 +1091,7 @@ static int stv_open (struct inode *inode, struct file *file) int err = 0; /* we are called with the BKL held */ + lock_kernel(); stv680->user = 1; err = stv_init (stv680); /* main initialization routine for camera */ @@ -1103,6 +1105,7 @@ static int stv_open (struct inode *inode, struct file *file) } if (err) stv680->user = 0; + unlock_kernel(); return err; } @@ -1406,9 +1409,7 @@ static const struct file_operations stv680_fops = { .llseek = no_llseek, }; static struct video_device stv680_template = { - .owner = THIS_MODULE, .name = "STV0680 USB camera", - .type = VID_TYPE_CAPTURE, .fops = &stv680_fops, .release = video_device_release, .minor = -1, diff --git a/linux/drivers/media/video/tda7432.c b/linux/drivers/media/video/tda7432.c index 1e70a7710..375b8d6d2 100644 --- a/linux/drivers/media/video/tda7432.c +++ b/linux/drivers/media/video/tda7432.c @@ -44,7 +44,7 @@ #include <linux/delay.h> #include <linux/errno.h> #include <linux/slab.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <linux/i2c.h> #include <media/v4l2-common.h> diff --git a/linux/drivers/media/video/tda9840.c b/linux/drivers/media/video/tda9840.c index f4ebfd84b..2d3d430c5 100644 --- a/linux/drivers/media/video/tda9840.c +++ b/linux/drivers/media/video/tda9840.c @@ -2,6 +2,7 @@ tda9840 - i2c-driver for the tda9840 by SGS Thomson Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> + Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> The tda9840 is a stereo/dual sound processor with digital identification. It can be found at address 0x84 on the i2c-bus. @@ -28,16 +29,19 @@ #include <linux/module.h> #include <linux/ioctl.h> #include <linux/i2c.h> +#include <media/v4l2-common.h> +#include <media/v4l2-i2c-drv-legacy.h> +#include "tda9840.h" #include "compat.h" -#include "tda9840.h" +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_DESCRIPTION("tda9840 driver"); +MODULE_LICENSE("GPL"); -static int debug; /* insmod parameter */ +static int debug; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); -#define dprintk(args...) \ - do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0) +MODULE_PARM_DESC(debug, "Debug level (0-1)"); #define SWITCH 0x00 #define LEVEL_ADJUST 0x02 @@ -50,18 +54,21 @@ static unsigned short normal_i2c[] = { I2C_ADDR_TDA9840, I2C_CLIENT_END }; /* magic definition of all other variables and things */ I2C_CLIENT_INSMOD; -static struct i2c_driver driver; -static struct i2c_client client_template; +static void tda9840_write(struct i2c_client *client, u8 reg, u8 val) +{ + if (i2c_smbus_write_byte_data(client, reg, val)) + v4l_dbg(1, debug, client, "error writing %02x to %02x\n", + val, reg); +} -static int command(struct i2c_client *client, unsigned int cmd, void *arg) +static int tda9840_command(struct i2c_client *client, unsigned cmd, void *arg) { int result; int byte = *(int *)arg; switch (cmd) { case TDA9840_SWITCH: - - dprintk("TDA9840_SWITCH: 0x%02x\n", byte); + v4l_dbg(1, debug, client, "TDA9840_SWITCH: 0x%02x\n", byte); if (byte != TDA9840_SET_MONO && byte != TDA9840_SET_MUTE @@ -74,14 +81,11 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg) return -EINVAL; } - result = i2c_smbus_write_byte_data(client, SWITCH, byte); - if (result) - dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result); + tda9840_write(client, SWITCH, byte); break; case TDA9840_LEVEL_ADJUST: - - dprintk("TDA9840_LEVEL_ADJUST: %d\n", byte); + v4l_dbg(1, debug, client, "TDA9840_LEVEL_ADJUST: %d\n", byte); /* check for correct range */ if (byte > 25 || byte < -20) @@ -93,15 +97,11 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg) byte += 0x8; else byte = -byte; - - result = i2c_smbus_write_byte_data(client, LEVEL_ADJUST, byte); - if (result) - dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result); + tda9840_write(client, LEVEL_ADJUST, byte); break; case TDA9840_STEREO_ADJUST: - - dprintk("TDA9840_STEREO_ADJUST: %d\n", byte); + v4l_dbg(1, debug, client, "TDA9840_STEREO_ADJUST: %d\n", byte); /* check for correct range */ if (byte > 25 || byte < -24) @@ -114,9 +114,7 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg) else byte = -byte; - result = i2c_smbus_write_byte_data(client, STEREO_ADJUST, byte); - if (result) - dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result); + tda9840_write(client, STEREO_ADJUST, byte); break; case TDA9840_DETECT: { @@ -124,29 +122,29 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg) byte = i2c_smbus_read_byte_data(client, STEREO_ADJUST); if (byte == -1) { - dprintk("i2c_smbus_read_byte_data() failed\n"); + v4l_dbg(1, debug, client, + "i2c_smbus_read_byte_data() failed\n"); return -EIO; } - if (0 != (byte & 0x80)) { - dprintk("TDA9840_DETECT: register contents invalid\n"); + if (byte & 0x80) { + v4l_dbg(1, debug, client, + "TDA9840_DETECT: register contents invalid\n"); return -EINVAL; } - dprintk("TDA9840_DETECT: byte: 0x%02x\n", byte); - *ret = ((byte & 0x60) >> 5); + v4l_dbg(1, debug, client, "TDA9840_DETECT: byte: 0x%02x\n", byte); + *ret = (byte & 0x60) >> 5; result = 0; break; } case TDA9840_TEST: - dprintk("TDA9840_TEST: 0x%02x\n", byte); + v4l_dbg(1, debug, client, "TDA9840_TEST: 0x%02x\n", byte); /* mask out irrelevant bits */ byte &= 0x3; - result = i2c_smbus_write_byte_data(client, TEST, byte); - if (result) - dprintk("i2c_smbus_write_byte() failed, ret:%d\n", result); + tda9840_write(client, TEST, byte); break; default: return -ENOIOCTLCMD; @@ -158,99 +156,55 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg) return 0; } -static int detect(struct i2c_adapter *adapter, int address, int kind) +static int tda9840_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - struct i2c_client *client; - int result = 0; - - int byte = 0x0; + int result; + int byte; /* let's see whether this adapter can support what we need */ - if (0 == i2c_check_functionality(adapter, - I2C_FUNC_SMBUS_READ_BYTE_DATA | - I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA | + I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) return 0; - } - /* allocate memory for client structure */ - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!client) { - printk("not enough kernel memory\n"); - return -ENOMEM; - } - - /* fill client structure */ - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->addr = address; - client->adapter = adapter; - - /* tell the i2c layer a new client has arrived */ - if (0 != (result = i2c_attach_client(client))) { - kfree(client); - return result; - } + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); /* set initial values for level & stereo - adjustment, mode */ byte = 0; - result = command(client, TDA9840_LEVEL_ADJUST, &byte); - result += command(client, TDA9840_STEREO_ADJUST, &byte); + result = tda9840_command(client, TDA9840_LEVEL_ADJUST, &byte); + result += tda9840_command(client, TDA9840_STEREO_ADJUST, &byte); byte = TDA9840_SET_MONO; - result = command(client, TDA9840_SWITCH, &byte); + result = tda9840_command(client, TDA9840_SWITCH, &byte); if (result) { - dprintk("could not initialize tda9840\n"); + v4l_dbg(1, debug, client, "could not initialize tda9840\n"); return -ENODEV; } - - printk("tda9840: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]); return 0; } -static int attach(struct i2c_adapter *adapter) +static int tda9840_legacy_probe(struct i2c_adapter *adapter) { - /* let's see whether this is a know adapter we can attach to */ - if (adapter->id != I2C_HW_SAA7146) { - dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id); - return -ENODEV; - } - - return i2c_probe(adapter, &addr_data, &detect); + /* Let's see whether this is a known adapter we can attach to. + Prevents conflicts with tvaudio.c. */ + return adapter->id == I2C_HW_SAA7146; } - -static int detach(struct i2c_client *client) -{ - int ret = i2c_detach_client(client); - kfree(client); - return ret; -} - -static struct i2c_driver driver = { - .driver = { - .name = "tda9840", - }, - .id = I2C_DRIVERID_TDA9840, - .attach_adapter = attach, - .detach_client = detach, - .command = command, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) +static const struct i2c_device_id tda9840_id[] = { + { "tda9840", 0 }, + { } }; +MODULE_DEVICE_TABLE(i2c, tda9840_id); +#endif -static struct i2c_client client_template = { +static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "tda9840", - .driver = &driver, + .driverid = I2C_DRIVERID_TDA9840, + .command = tda9840_command, + .probe = tda9840_probe, + .legacy_probe = tda9840_legacy_probe, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) + .id_table = tda9840_id, +#endif }; - -static int __init this_module_init(void) -{ - return i2c_add_driver(&driver); -} - -static void __exit this_module_exit(void) -{ - i2c_del_driver(&driver); -} - -module_init(this_module_init); -module_exit(this_module_exit); - -MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); -MODULE_DESCRIPTION("tda9840 driver"); -MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/tda9875.c b/linux/drivers/media/video/tda9875.c index 5c3d43082..20e738264 100644 --- a/linux/drivers/media/video/tda9875.c +++ b/linux/drivers/media/video/tda9875.c @@ -25,7 +25,7 @@ #include <linux/delay.h> #include <linux/errno.h> #include <linux/slab.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <media/v4l2-common.h> #include <linux/i2c.h> #include <linux/init.h> diff --git a/linux/drivers/media/video/tea6415c.c b/linux/drivers/media/video/tea6415c.c index da654bd15..073f020fa 100644 --- a/linux/drivers/media/video/tea6415c.c +++ b/linux/drivers/media/video/tea6415c.c @@ -2,6 +2,7 @@ tea6415c - i2c-driver for the tea6415c by SGS Thomson Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> + Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> The tea6415c is a bus controlled video-matrix-switch with 8 inputs and 6 outputs. @@ -30,19 +31,19 @@ #include <linux/module.h> #include <linux/ioctl.h> #include <linux/i2c.h> +#include <media/v4l2-common.h> +#include <media/v4l2-i2c-drv-legacy.h> +#include "tea6415c.h" #include "compat.h" -#include "tea6415c.h" +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_DESCRIPTION("tea6415c driver"); +MODULE_LICENSE("GPL"); -static int debug; /* insmod parameter */ +static int debug; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); - -#define dprintk(args...) \ - do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0) -#define TEA6415C_NUM_INPUTS 8 -#define TEA6415C_NUM_OUTPUTS 6 +MODULE_PARM_DESC(debug, "Debug level (0-1)"); /* addresses to scan, found only at 0x03 and/or 0x43 (7-bit) */ static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIENT_END }; @@ -50,60 +51,6 @@ static unsigned short normal_i2c[] = { I2C_TEA6415C_1, I2C_TEA6415C_2, I2C_CLIEN /* magic definition of all other variables and things */ I2C_CLIENT_INSMOD; -static struct i2c_driver driver; -static struct i2c_client client_template; - -/* this function is called by i2c_probe */ -static int detect(struct i2c_adapter *adapter, int address, int kind) -{ - struct i2c_client *client = NULL; - int err = 0; - - /* let's see whether this adapter can support what we need */ - if (0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) { - return 0; - } - - /* allocate memory for client structure */ - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!client) { - return -ENOMEM; - } - - /* fill client structure */ - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->addr = address; - client->adapter = adapter; - - /* tell the i2c layer a new client has arrived */ - if (0 != (err = i2c_attach_client(client))) { - kfree(client); - return err; - } - - printk("tea6415c: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]); - - return 0; -} - -static int attach(struct i2c_adapter *adapter) -{ - /* let's see whether this is a know adapter we can attach to */ - if (adapter->id != I2C_HW_SAA7146) { - dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id); - return -ENODEV; - } - - return i2c_probe(adapter, &addr_data, &detect); -} - -static int detach(struct i2c_client *client) -{ - int ret = i2c_detach_client(client); - kfree(client); - return ret; -} - /* makes a connection between the input-pin 'i' and the output-pin 'o' for the tea6415c-client 'client' */ static int switch_matrix(struct i2c_client *client, int i, int o) @@ -111,7 +58,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); + v4l_dbg(1, debug, client, "i=%d, o=%d\n", i, o); /* check if the pins are valid */ if (0 == ((1 == i || 3 == i || 5 == i || 6 == i || 8 == i || 10 == i || 20 == i || 11 == i) @@ -169,14 +116,14 @@ static int switch_matrix(struct i2c_client *client, int i, int o) ret = i2c_smbus_write_byte(client, byte); if (ret) { - dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret); + v4l_dbg(1, debug, client, + "i2c_smbus_write_byte() failed, ret:%d\n", ret); return -EIO; } - return ret; } -static int command(struct i2c_client *client, unsigned int cmd, void *arg) +static int tea6415c_command(struct i2c_client *client, unsigned cmd, void *arg) { struct tea6415c_multiplex *v = (struct tea6415c_multiplex *)arg; int result = 0; @@ -188,38 +135,44 @@ static int command(struct i2c_client *client, unsigned int cmd, void *arg) default: return -ENOIOCTLCMD; } - return result; } -static struct i2c_driver driver = { - .driver = { - .name = "tea6415c", - }, - .id = I2C_DRIVERID_TEA6415C, - .attach_adapter = attach, - .detach_client = detach, - .command = command, -}; - -static struct i2c_client client_template = { - .name = "tea6415c", - .driver = &driver, -}; - -static int __init this_module_init(void) +/* this function is called by i2c_probe */ +static int tea6415c_probe(struct i2c_client *client, + const struct i2c_device_id *id) { - return i2c_add_driver(&driver); + /* let's see whether this adapter can support what we need */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) + return 0; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + return 0; } -static void __exit this_module_exit(void) +static int tea6415c_legacy_probe(struct i2c_adapter *adapter) { - i2c_del_driver(&driver); + /* Let's see whether this is a known adapter we can attach to. + Prevents conflicts with tvaudio.c. */ + return adapter->id == I2C_HW_SAA7146; } -module_init(this_module_init); -module_exit(this_module_exit); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) +static const struct i2c_device_id tea6415c_id[] = { + { "tea6415c", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, tea6415c_id); +#endif -MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); -MODULE_DESCRIPTION("tea6415c driver"); -MODULE_LICENSE("GPL"); +static struct v4l2_i2c_driver_data v4l2_i2c_data = { + .name = "tea6415c", + .driverid = I2C_DRIVERID_TEA6415C, + .command = tea6415c_command, + .probe = tea6415c_probe, + .legacy_probe = tea6415c_legacy_probe, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) + .id_table = tea6415c_id, +#endif +}; diff --git a/linux/drivers/media/video/tea6420.c b/linux/drivers/media/video/tea6420.c index d0c63703c..8ded72ade 100644 --- a/linux/drivers/media/video/tea6420.c +++ b/linux/drivers/media/video/tea6420.c @@ -2,6 +2,7 @@ tea6420 - i2c-driver for the tea6420 by SGS Thomson Copyright (C) 1998-2003 Michael Hunold <michael@mihu.de> + Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl> The tea6420 is a bus controlled audio-matrix with 5 stereo inputs, 4 stereo outputs and gain control for each output. @@ -30,16 +31,19 @@ #include <linux/module.h> #include <linux/ioctl.h> #include <linux/i2c.h> +#include <media/v4l2-common.h> +#include <media/v4l2-i2c-drv-legacy.h> +#include "tea6420.h" #include "compat.h" -#include "tea6420.h" +MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); +MODULE_DESCRIPTION("tea6420 driver"); +MODULE_LICENSE("GPL"); -static int debug; /* insmod parameter */ +static int debug; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off)."); -#define dprintk(args...) \ - do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0) +MODULE_PARM_DESC(debug, "Debug level (0-1)"); /* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */ static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END }; @@ -47,23 +51,20 @@ static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I /* magic definition of all other variables and things */ I2C_CLIENT_INSMOD; -static struct i2c_driver driver; -static struct i2c_client client_template; - /* make a connection between the input 'i' and the output 'o' with gain 'g' for the tea6420-client 'client' (note: i = 6 means 'mute') */ static int tea6420_switch(struct i2c_client *client, int i, int o, int g) { - u8 byte = 0; + u8 byte; int ret; - dprintk("adr:0x%02x, i:%d, o:%d, g:%d\n", client->addr, i, o, g); + v4l_dbg(1, debug, client, "i=%d, o=%d, g=%d\n", i, o, g); /* check if the parameters are valid */ if (i < 1 || i > 6 || o < 1 || o > 4 || g < 0 || g > 6 || g % 2 != 0) return -1; - byte = ((o - 1) << 5); + byte = ((o - 1) << 5); byte |= (i - 1); /* to understand this, have a look at the tea6420-specs (p.5) */ @@ -83,40 +84,41 @@ static int tea6420_switch(struct i2c_client *client, int i, int o, int g) ret = i2c_smbus_write_byte(client, byte); if (ret) { - dprintk("i2c_smbus_write_byte() failed, ret:%d\n", ret); + v4l_dbg(1, debug, client, + "i2c_smbus_write_byte() failed, ret:%d\n", ret); return -EIO; } - return 0; } -/* this function is called by i2c_probe */ -static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind) +static int tea6420_command(struct i2c_client *client, unsigned cmd, void *arg) { - struct i2c_client *client; - int err = 0, i = 0; + struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg; + int result = 0; - /* let's see whether this adapter can support what we need */ - if (0 == i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) { - return 0; + switch (cmd) { + case TEA6420_SWITCH: + result = tea6420_switch(client, a->in, a->out, a->gain); + break; + default: + return -ENOIOCTLCMD; } - /* allocate memory for client structure */ - client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (!client) { - return -ENOMEM; - } + return result; +} - /* fill client structure */ - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->addr = address; - client->adapter = adapter; +/* this function is called by i2c_probe */ +static int tea6420_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err, i; - /* tell the i2c layer a new client has arrived */ - if (0 != (err = i2c_attach_client(client))) { - kfree(client); - return err; - } + /* let's see whether this adapter can support what we need */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE)) + return -EIO; + + v4l_info(client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); /* set initial values: set "mute"-input to all outputs at gain 0 */ err = 0; @@ -124,78 +126,35 @@ static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind) err += tea6420_switch(client, 6, i, 0); } if (err) { - dprintk("could not initialize tea6420\n"); + v4l_dbg(1, debug, client, "could not initialize tea6420\n"); kfree(client); return -ENODEV; } - - printk("tea6420: detected @ 0x%02x on adapter %s\n", address, &client->adapter->name[0]); - return 0; } -static int attach(struct i2c_adapter *adapter) +static int tea6420_legacy_probe(struct i2c_adapter *adapter) { - /* let's see whether this is a know adapter we can attach to */ - if (adapter->id != I2C_HW_SAA7146) { - dprintk("refusing to probe on unknown adapter [name='%s',id=0x%x]\n", adapter->name, adapter->id); - return -ENODEV; - } - - return i2c_probe(adapter, &addr_data, &tea6420_detect); -} - -static int detach(struct i2c_client *client) -{ - int ret = i2c_detach_client(client); - kfree(client); - return ret; -} - -static int command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct tea6420_multiplex *a = (struct tea6420_multiplex *)arg; - int result = 0; - - switch (cmd) { - case TEA6420_SWITCH: - result = tea6420_switch(client, a->in, a->out, a->gain); - break; - default: - return -ENOIOCTLCMD; - } - - return result; + /* Let's see whether this is a known adapter we can attach to. + Prevents conflicts with tvaudio.c. */ + return adapter->id == I2C_HW_SAA7146; } -static struct i2c_driver driver = { - .driver = { - .name = "tea6420", - }, - .id = I2C_DRIVERID_TEA6420, - .attach_adapter = attach, - .detach_client = detach, - .command = command, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) +static const struct i2c_device_id tea6420_id[] = { + { "tea6420", 0 }, + { } }; +MODULE_DEVICE_TABLE(i2c, tea6420_id); +#endif -static struct i2c_client client_template = { +static struct v4l2_i2c_driver_data v4l2_i2c_data = { .name = "tea6420", - .driver = &driver, + .driverid = I2C_DRIVERID_TEA6420, + .command = tea6420_command, + .probe = tea6420_probe, + .legacy_probe = tea6420_legacy_probe, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) + .id_table = tea6420_id, +#endif }; - -static int __init this_module_init(void) -{ - return i2c_add_driver(&driver); -} - -static void __exit this_module_exit(void) -{ - i2c_del_driver(&driver); -} - -module_init(this_module_init); -module_exit(this_module_exit); - -MODULE_AUTHOR("Michael Hunold <michael@mihu.de>"); -MODULE_DESCRIPTION("tea6420 driver"); -MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/tlv320aic23b.c b/linux/drivers/media/video/tlv320aic23b.c index b601c232a..a531a46d1 100644 --- a/linux/drivers/media/video/tlv320aic23b.c +++ b/linux/drivers/media/video/tlv320aic23b.c @@ -29,7 +29,7 @@ #include <asm/uaccess.h> #include <linux/i2c.h> #include <linux/i2c-id.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/v4l2-i2c-drv-legacy.h> #include "compat.h" diff --git a/linux/drivers/media/video/tuner-3036.c b/linux/drivers/media/video/tuner-3036.c deleted file mode 100644 index 8b87d75f4..000000000 --- a/linux/drivers/media/video/tuner-3036.c +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Driver for Philips SAB3036 "CITAC" tuner control chip. - * - * Author: Phil Blundell <philb@gnu.org> - * - * The SAB3036 is just about different enough from the chips that - * tuner.c copes with to make it not worth the effort to crowbar - * the support into that file. So instead we have a separate driver. - * - * 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. - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/string.h> -#include <linux/timer.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/slab.h> -#include <linux/init.h> - -#include <linux/i2c.h> -#include "compat.h" -#include <linux/videodev.h> -#include <media/v4l2-common.h> - -#include <media/tuner.h> - -static int debug; /* insmod parameter */ -static int this_adap; - -static struct i2c_client client_template; - -/* Addresses to scan */ -static unsigned short normal_i2c[] = { 0x60, 0x61, I2C_CLIENT_END }; -static unsigned short ignore = I2C_CLIENT_END; - -static struct i2c_client_address_data addr_data = { - .normal_i2c = normal_i2c, - .probe = &ignore, - .ignore = &ignore, -}; - -/* ---------------------------------------------------------------------- */ - -static unsigned char -tuner_getstatus (struct i2c_client *c) -{ - unsigned char byte; - if (i2c_master_recv(c, &byte, 1) != 1) - printk(KERN_ERR "tuner-3036: I/O error.\n"); - return byte; -} - -#define TUNER_FL 0x80 - -static int -tuner_islocked (struct i2c_client *c) -{ - return (tuner_getstatus(c) & TUNER_FL); -} - -/* ---------------------------------------------------------------------- */ - -static void -set_tv_freq(struct i2c_client *c, int freq) -{ - u16 div = ((freq * 20) / 16); - unsigned long give_up = jiffies + HZ; - unsigned char buffer[2]; - - if (debug) - printk(KERN_DEBUG "tuner: setting frequency %dMHz, divisor %x\n", freq / 16, div); - - /* Select high tuning current */ - buffer[0] = 0x29; - buffer[1] = 0x3e; - - if (i2c_master_send(c, buffer, 2) != 2) - printk("tuner: i2c i/o error 1\n"); - - buffer[0] = 0x80 | ((div>>8) & 0x7f); - buffer[1] = div & 0xff; - - if (i2c_master_send(c, buffer, 2) != 2) - printk("tuner: i2c i/o error 2\n"); - - while (!tuner_islocked(c) && time_before(jiffies, give_up)) - schedule(); - - if (!tuner_islocked(c)) - printk(KERN_WARNING "tuner: failed to achieve PLL lock\n"); - - /* Select low tuning current and engage AFC */ - buffer[0] = 0x29; - buffer[1] = 0xb2; - - if (i2c_master_send(c, buffer, 2) != 2) - printk("tuner: i2c i/o error 3\n"); - - if (debug) - printk(KERN_DEBUG "tuner: status %02x\n", tuner_getstatus(c)); -} - -/* ---------------------------------------------------------------------- */ - -static int -tuner_attach(struct i2c_adapter *adap, int addr, int kind) -{ - static unsigned char buffer[] = { 0x29, 0x32, 0x2a, 0, 0x2b, 0 }; - - struct i2c_client *client; - - if (this_adap > 0) - return -1; - this_adap++; - - client_template.adapter = adap; - client_template.addr = addr; - - client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); - if (client == NULL) - return -ENOMEM; - memcpy(client, &client_template, sizeof(struct i2c_client)); - - printk("tuner: SAB3036 found, status %02x\n", tuner_getstatus(client)); - - i2c_attach_client(client); - - if (i2c_master_send(client, buffer, 2) != 2) - printk("tuner: i2c i/o error 1\n"); - if (i2c_master_send(client, buffer+2, 2) != 2) - printk("tuner: i2c i/o error 2\n"); - if (i2c_master_send(client, buffer+4, 2) != 2) - printk("tuner: i2c i/o error 3\n"); - return 0; -} - -static int -tuner_detach(struct i2c_client *c) -{ - return 0; -} - -static int -tuner_command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - int *iarg = (int*)arg; - - switch (cmd) - { - case VIDIOCSFREQ: - set_tv_freq(client, *iarg); - break; - - default: - return -EINVAL; - } - return 0; -} - -static int -tuner_probe(struct i2c_adapter *adap) -{ - this_adap = 0; - if (adap->id == I2C_HW_B_LP) - return i2c_probe(adap, &addr_data, tuner_attach); - return 0; -} - -/* ----------------------------------------------------------------------- */ - -static struct i2c_driver -i2c_driver_tuner = -{ - .driver = { - .name = "sab3036", - }, - .id = I2C_DRIVERID_SAB3036, - .attach_adapter = tuner_probe, - .detach_client = tuner_detach, - .command = tuner_command -}; - -static struct i2c_client client_template = -{ - .driver = &i2c_driver_tuner, - .name = "SAB3036", -}; - -static int __init -tuner3036_init(void) -{ - return i2c_add_driver(&i2c_driver_tuner); -} - -static void __exit -tuner3036_exit(void) -{ - i2c_del_driver(&i2c_driver_tuner); -} - -MODULE_DESCRIPTION("SAB3036 tuner driver"); -MODULE_AUTHOR("Philip Blundell <philb@gnu.org>"); -MODULE_LICENSE("GPL"); - -module_param(debug, int, 0); -MODULE_PARM_DESC(debug,"Enable debugging output"); - -module_init(tuner3036_init); -module_exit(tuner3036_exit); diff --git a/linux/drivers/media/video/tveeprom.c b/linux/drivers/media/video/tveeprom.c index dc0bd9fda..5f088e669 100644 --- a/linux/drivers/media/video/tveeprom.c +++ b/linux/drivers/media/video/tveeprom.c @@ -34,13 +34,13 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/types.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <linux/i2c.h> #include <media/tuner.h> #include <media/tveeprom.h> #include <media/v4l2-common.h> -#include <media/audiochip.h> +#include <media/v4l2-chip-ident.h> #include "compat.h" MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver"); @@ -262,70 +262,72 @@ hauppauge_tuner[] = { TUNER_ABSENT, "MaxLinear MXL5005_v2"}, { TUNER_PHILIPS_TDA8290, "Philips 18271_8295"}, /* 150-159 */ - { TUNER_ABSENT, "Xceive XC5000"}, + { TUNER_ABSENT, "Xceive XC5000"}, }; +/* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are + * internal to a video chip, i.e. not a separate audio chip. */ static struct HAUPPAUGE_AUDIOIC { - enum audiochip id; + u32 id; char *name; } audioIC[] = { /* 0-4 */ - {AUDIO_CHIP_NONE, "None"}, - {AUDIO_CHIP_TEA6300, "TEA6300"}, - {AUDIO_CHIP_TEA6300, "TEA6320"}, - {AUDIO_CHIP_TDA985X, "TDA9850"}, - {AUDIO_CHIP_MSP34XX, "MSP3400C"}, + { V4L2_IDENT_NONE, "None" }, + { V4L2_IDENT_UNKNOWN, "TEA6300" }, + { V4L2_IDENT_UNKNOWN, "TEA6320" }, + { V4L2_IDENT_UNKNOWN, "TDA9850" }, + { V4L2_IDENT_MSPX4XX, "MSP3400C" }, /* 5-9 */ - {AUDIO_CHIP_MSP34XX, "MSP3410D"}, - {AUDIO_CHIP_MSP34XX, "MSP3415"}, - {AUDIO_CHIP_MSP34XX, "MSP3430"}, - {AUDIO_CHIP_MSP34XX, "MSP3438"}, - {AUDIO_CHIP_UNKNOWN, "CS5331"}, + { V4L2_IDENT_MSPX4XX, "MSP3410D" }, + { V4L2_IDENT_MSPX4XX, "MSP3415" }, + { V4L2_IDENT_MSPX4XX, "MSP3430" }, + { V4L2_IDENT_MSPX4XX, "MSP3438" }, + { V4L2_IDENT_UNKNOWN, "CS5331" }, /* 10-14 */ - {AUDIO_CHIP_MSP34XX, "MSP3435"}, - {AUDIO_CHIP_MSP34XX, "MSP3440"}, - {AUDIO_CHIP_MSP34XX, "MSP3445"}, - {AUDIO_CHIP_MSP34XX, "MSP3411"}, - {AUDIO_CHIP_MSP34XX, "MSP3416"}, + { V4L2_IDENT_MSPX4XX, "MSP3435" }, + { V4L2_IDENT_MSPX4XX, "MSP3440" }, + { V4L2_IDENT_MSPX4XX, "MSP3445" }, + { V4L2_IDENT_MSPX4XX, "MSP3411" }, + { V4L2_IDENT_MSPX4XX, "MSP3416" }, /* 15-19 */ - {AUDIO_CHIP_MSP34XX, "MSP3425"}, - {AUDIO_CHIP_MSP34XX, "MSP3451"}, - {AUDIO_CHIP_MSP34XX, "MSP3418"}, - {AUDIO_CHIP_UNKNOWN, "Type 0x12"}, - {AUDIO_CHIP_UNKNOWN, "OKI7716"}, + { V4L2_IDENT_MSPX4XX, "MSP3425" }, + { V4L2_IDENT_MSPX4XX, "MSP3451" }, + { V4L2_IDENT_MSPX4XX, "MSP3418" }, + { V4L2_IDENT_UNKNOWN, "Type 0x12" }, + { V4L2_IDENT_UNKNOWN, "OKI7716" }, /* 20-24 */ - {AUDIO_CHIP_MSP34XX, "MSP4410"}, - {AUDIO_CHIP_MSP34XX, "MSP4420"}, - {AUDIO_CHIP_MSP34XX, "MSP4440"}, - {AUDIO_CHIP_MSP34XX, "MSP4450"}, - {AUDIO_CHIP_MSP34XX, "MSP4408"}, + { V4L2_IDENT_MSPX4XX, "MSP4410" }, + { V4L2_IDENT_MSPX4XX, "MSP4420" }, + { V4L2_IDENT_MSPX4XX, "MSP4440" }, + { V4L2_IDENT_MSPX4XX, "MSP4450" }, + { V4L2_IDENT_MSPX4XX, "MSP4408" }, /* 25-29 */ - {AUDIO_CHIP_MSP34XX, "MSP4418"}, - {AUDIO_CHIP_MSP34XX, "MSP4428"}, - {AUDIO_CHIP_MSP34XX, "MSP4448"}, - {AUDIO_CHIP_MSP34XX, "MSP4458"}, - {AUDIO_CHIP_MSP34XX, "Type 0x1d"}, + { V4L2_IDENT_MSPX4XX, "MSP4418" }, + { V4L2_IDENT_MSPX4XX, "MSP4428" }, + { V4L2_IDENT_MSPX4XX, "MSP4448" }, + { V4L2_IDENT_MSPX4XX, "MSP4458" }, + { V4L2_IDENT_MSPX4XX, "Type 0x1d" }, /* 30-34 */ - {AUDIO_CHIP_INTERNAL, "CX880"}, - {AUDIO_CHIP_INTERNAL, "CX881"}, - {AUDIO_CHIP_INTERNAL, "CX883"}, - {AUDIO_CHIP_INTERNAL, "CX882"}, - {AUDIO_CHIP_INTERNAL, "CX25840"}, + { V4L2_IDENT_AMBIGUOUS, "CX880" }, + { V4L2_IDENT_AMBIGUOUS, "CX881" }, + { V4L2_IDENT_AMBIGUOUS, "CX883" }, + { V4L2_IDENT_AMBIGUOUS, "CX882" }, + { V4L2_IDENT_AMBIGUOUS, "CX25840" }, /* 35-39 */ - {AUDIO_CHIP_INTERNAL, "CX25841"}, - {AUDIO_CHIP_INTERNAL, "CX25842"}, - {AUDIO_CHIP_INTERNAL, "CX25843"}, - {AUDIO_CHIP_INTERNAL, "CX23418"}, - {AUDIO_CHIP_INTERNAL, "CX23885"}, + { V4L2_IDENT_AMBIGUOUS, "CX25841" }, + { V4L2_IDENT_AMBIGUOUS, "CX25842" }, + { V4L2_IDENT_AMBIGUOUS, "CX25843" }, + { V4L2_IDENT_AMBIGUOUS, "CX23418" }, + { V4L2_IDENT_AMBIGUOUS, "CX23885" }, /* 40-44 */ - {AUDIO_CHIP_INTERNAL, "CX23888"}, - {AUDIO_CHIP_INTERNAL, "SAA7131"}, - {AUDIO_CHIP_INTERNAL, "CX23887"}, - {AUDIO_CHIP_INTERNAL, "SAA7164"}, - {AUDIO_CHIP_INTERNAL, "AU8522"}, + { V4L2_IDENT_AMBIGUOUS, "CX23888" }, + { V4L2_IDENT_AMBIGUOUS, "SAA7131" }, + { V4L2_IDENT_AMBIGUOUS, "CX23887" }, + { V4L2_IDENT_AMBIGUOUS, "SAA7164" }, + { V4L2_IDENT_AMBIGUOUS, "AU8522" }, }; /* This list is supplied by Hauppauge. Thanks! */ @@ -484,7 +486,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tvee->has_radio = eeprom_data[i+len-1]; /* old style tag, don't know how to detect IR presence, mark as unknown. */ - tvee->has_ir = -1; + tvee->has_ir = 0; tvee->model = eeprom_data[i+8] + (eeprom_data[i+9] << 8); @@ -510,7 +512,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, if (audioic < ARRAY_SIZE(audioIC)) tvee->audio_processor = audioIC[audioic].id; else - tvee->audio_processor = AUDIO_CHIP_UNKNOWN; + tvee->audio_processor = V4L2_IDENT_UNKNOWN; break; /* case 0x03: tag 'EEInfo' */ @@ -543,7 +545,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, if (audioic < ARRAY_SIZE(audioIC)) tvee->audio_processor = audioIC[audioic].id; else - tvee->audio_processor = AUDIO_CHIP_UNKNOWN; + tvee->audio_processor = V4L2_IDENT_UNKNOWN; break; @@ -604,7 +606,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, case 0x0f: /* tag 'IRInfo' */ - tvee->has_ir = eeprom_data[i+1]; + tvee->has_ir = 1 | (eeprom_data[i+1] << 1); break; /* case 0x10: tag 'VBIInfo' */ @@ -691,7 +693,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, t_fmt_name2[6], t_fmt_name2[7], t_format2); if (audioic < 0) { tveeprom_info("audio processor is unknown (no idx)\n"); - tvee->audio_processor = AUDIO_CHIP_UNKNOWN; + tvee->audio_processor = V4L2_IDENT_UNKNOWN; } else { if (audioic < ARRAY_SIZE(audioIC)) tveeprom_info("audio processor is %s (idx %d)\n", @@ -704,14 +706,14 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, tveeprom_info("decoder processor is %s (idx %d)\n", STRM(decoderIC, tvee->decoder_processor), tvee->decoder_processor); - if (tvee->has_ir == -1) - tveeprom_info("has %sradio\n", - tvee->has_radio ? "" : "no "); - else + if (tvee->has_ir) tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n", tvee->has_radio ? "" : "no ", - (tvee->has_ir & 1) ? "" : "no ", - (tvee->has_ir & 2) ? "" : "no "); + (tvee->has_ir & 2) ? "" : "no ", + (tvee->has_ir & 4) ? "" : "no "); + else + tveeprom_info("has %sradio\n", + tvee->has_radio ? "" : "no "); } EXPORT_SYMBOL(tveeprom_hauppauge_analog); diff --git a/linux/drivers/media/video/tvmixer.c b/linux/drivers/media/video/tvmixer.c index d7b931fd3..fd2e902ea 100644 --- a/linux/drivers/media/video/tvmixer.c +++ b/linux/drivers/media/video/tvmixer.c @@ -9,6 +9,7 @@ #include <linux/errno.h> #include <linux/slab.h> #include <linux/i2c.h> +#include <linux/smp_lock.h> #include "compat.h" #include <linux/videodev.h> #include <linux/init.h> @@ -16,7 +17,6 @@ #include <linux/sound.h> #include <linux/soundcard.h> -#include <asm/semaphore.h> #include <asm/uaccess.h> #define DEV_MAX 4 @@ -183,6 +183,7 @@ static int tvmixer_open(struct inode *inode, struct file *file) struct TVMIXER *mix = NULL; struct i2c_client *client = NULL; + lock_kernel(); for (i = 0; i < DEV_MAX; i++) { if (devices[i].minor == minor) { mix = devices+i; @@ -191,13 +192,16 @@ static int tvmixer_open(struct inode *inode, struct file *file) } } - if (NULL == client) + if (NULL == client) { + unlock_kernel(); return -ENODEV; + } /* lock bttv in memory while the mixer is in use */ file->private_data = mix; if (client->adapter->owner) try_module_get(client->adapter->owner); + unlock_kernel(); return 0; } diff --git a/linux/drivers/media/video/tvp5150.c b/linux/drivers/media/video/tvp5150.c index 6ac63245d..28c5c6761 100644 --- a/linux/drivers/media/video/tvp5150.c +++ b/linux/drivers/media/video/tvp5150.c @@ -7,7 +7,7 @@ #include <linux/i2c.h> #include "compat.h" -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <linux/delay.h> #include <linux/video_decoder.h> #include <media/v4l2-common.h> diff --git a/linux/drivers/media/video/usbvideo/usbvideo.c b/linux/drivers/media/video/usbvideo/usbvideo.c index f399db543..4b28a6dfb 100644 --- a/linux/drivers/media/video/usbvideo/usbvideo.c +++ b/linux/drivers/media/video/usbvideo/usbvideo.c @@ -952,8 +952,6 @@ static const struct file_operations usbvideo_fops = { .llseek = no_llseek, }; static const struct video_device usbvideo_template = { - .owner = THIS_MODULE, - .type = VID_TYPE_CAPTURE, .fops = &usbvideo_fops, }; @@ -1008,6 +1006,10 @@ allocate_done: EXPORT_SYMBOL(usbvideo_AllocateDevice); +static void usbvideo_dummy_release(struct video_device *vfd) +{ +} + int usbvideo_RegisterVideoDevice(struct uvd *uvd) { char tmp1[20], tmp2[20]; /* Buffers for printing */ @@ -1041,7 +1043,8 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) return -EINVAL; } uvd->vdev.parent = &uvd->dev->dev; - if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + uvd->vdev.release = usbvideo_dummy_release; + if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { err("%s: video_register_device failed", __func__); return -EPIPE; } diff --git a/linux/drivers/media/video/usbvideo/vicam.c b/linux/drivers/media/video/usbvideo/vicam.c index 2aa05f7ca..e7330fe4f 100644 --- a/linux/drivers/media/video/usbvideo/vicam.c +++ b/linux/drivers/media/video/usbvideo/vicam.c @@ -41,6 +41,7 @@ #include <linux/videodev.h> #include <linux/usb.h> #include <linux/vmalloc.h> +#include <linux/mm.h> #include <linux/slab.h> #include <linux/mutex.h> #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) @@ -797,20 +798,24 @@ vicam_open(struct inode *inode, struct file *file) * rely on this fact forever. */ + lock_kernel(); if (cam->open_count > 0) { printk(KERN_INFO "vicam_open called on already opened camera"); + unlock_kernel(); return -EBUSY; } cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL); if (!cam->raw_image) { + unlock_kernel(); return -ENOMEM; } cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); if (!cam->framebuf) { kfree(cam->raw_image); + unlock_kernel(); return -ENOMEM; } @@ -818,6 +823,7 @@ vicam_open(struct inode *inode, struct file *file) if (!cam->cntrlbuf) { kfree(cam->raw_image); rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES); + unlock_kernel(); return -ENOMEM; } @@ -835,6 +841,7 @@ vicam_open(struct inode *inode, struct file *file) cam->open_count++; file->private_data = cam; + unlock_kernel(); return 0; } @@ -1101,9 +1108,7 @@ static const struct file_operations vicam_fops = { }; static struct video_device vicam_template = { - .owner = THIS_MODULE, .name = "ViCam-based USB Camera", - .type = VID_TYPE_CAPTURE, .fops = &vicam_fops, .minor = -1, }; diff --git a/linux/drivers/media/video/usbvision/usbvision-core.c b/linux/drivers/media/video/usbvision/usbvision-core.c index bf464540c..8c2b53513 100644 --- a/linux/drivers/media/video/usbvision/usbvision-core.c +++ b/linux/drivers/media/video/usbvision/usbvision-core.c @@ -30,7 +30,6 @@ #include <linux/mm.h> #include <linux/utsname.h> #include <linux/highmem.h> -#include <linux/videodev.h> #include <linux/vmalloc.h> #include <linux/module.h> #include <linux/init.h> @@ -43,7 +42,6 @@ #include <media/saa7115.h> #include <media/v4l2-common.h> #include <media/tuner.h> -#include <media/audiochip.h> #include <linux/workqueue.h> diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c index 56cd685d3..b76295a5b 100644 --- a/linux/drivers/media/video/usbvision/usbvision-video.c +++ b/linux/drivers/media/video/usbvision/usbvision-video.c @@ -53,7 +53,6 @@ #include <linux/mm.h> #include <linux/utsname.h> #include <linux/highmem.h> -#include <linux/videodev.h> #include <linux/vmalloc.h> #include <linux/module.h> #include <linux/init.h> @@ -67,7 +66,6 @@ #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <media/tuner.h> -#include <media/audiochip.h> #include <linux/workqueue.h> @@ -369,6 +367,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) PDEBUG(DBG_IO, "open"); + lock_kernel(); usbvision_reset_powerOffTimer(usbvision); if (usbvision->user) @@ -426,6 +425,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) usbvision_empty_framequeues(usbvision); PDEBUG(DBG_IO, "success"); + unlock_kernel(); return errCode; } @@ -1371,13 +1371,8 @@ static const struct file_operations usbvision_fops = { /* .poll = video_poll, */ .compat_ioctl = v4l_compat_ioctl32, }; -static struct video_device usbvision_video_template = { - .owner = THIS_MODULE, - .type = VID_TYPE_TUNER | VID_TYPE_CAPTURE, - .fops = &usbvision_fops, - .name = "usbvision-video", - .release = video_device_release, - .minor = -1, + +static const struct v4l2_ioctl_ops usbvision_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1409,6 +1404,14 @@ static struct video_device usbvision_video_template = { .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif +}; + +static struct video_device usbvision_video_template = { + .fops = &usbvision_fops, + .ioctl_ops = &usbvision_ioctl_ops, + .name = "usbvision-video", + .release = video_device_release, + .minor = -1, .tvnorms = USBVISION_NORMS, .current_norm = V4L2_STD_PAL }; @@ -1424,14 +1427,7 @@ static const struct file_operations usbvision_radio_fops = { .compat_ioctl = v4l_compat_ioctl32, }; -static struct video_device usbvision_radio_template= -{ - .owner = THIS_MODULE, - .type = VID_TYPE_TUNER, - .fops = &usbvision_radio_fops, - .name = "usbvision-radio", - .release = video_device_release, - .minor = -1, +static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, @@ -1445,6 +1441,14 @@ static struct video_device usbvision_radio_template= .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, +}; + +static struct video_device usbvision_radio_template = { + .fops = &usbvision_radio_fops, + .name = "usbvision-radio", + .release = video_device_release, + .minor = -1, + .ioctl_ops = &usbvision_radio_ioctl_ops, .tvnorms = USBVISION_NORMS, .current_norm = V4L2_STD_PAL @@ -1462,8 +1466,6 @@ static const struct file_operations usbvision_vbi_fops = { static struct video_device usbvision_vbi_template= { - .owner = THIS_MODULE, - .type = VID_TYPE_TUNER, .fops = &usbvision_vbi_fops, .release = video_device_release, .name = "usbvision-vbi", diff --git a/linux/drivers/media/video/uvc/uvc_ctrl.c b/linux/drivers/media/video/uvc/uvc_ctrl.c index 3ae955126..6ef3e5297 100644 --- a/linux/drivers/media/video/uvc/uvc_ctrl.c +++ b/linux/drivers/media/video/uvc/uvc_ctrl.c @@ -195,8 +195,8 @@ static struct uvc_menu_info power_line_frequency_controls[] = { }; static struct uvc_menu_info exposure_auto_controls[] = { - { 1, "Manual Mode" }, { 2, "Auto Mode" }, + { 1, "Manual Mode" }, { 4, "Shutter Priority Mode" }, { 8, "Aperture Priority Mode" }, }; @@ -585,13 +585,18 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, struct uvc_control_mapping *mapping; struct uvc_menu_info *menu; unsigned int i; - __u8 data[8]; + __u8 *data; int ret; ctrl = uvc_find_control(video, v4l2_ctrl->id, &mapping); if (ctrl == NULL) return -EINVAL; + data = kmalloc(8, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + + memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl); v4l2_ctrl->id = mapping->id; v4l2_ctrl->type = mapping->v4l2_type; strncpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name); @@ -603,12 +608,13 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, if (ctrl->info->flags & UVC_CONTROL_GET_DEF) { if ((ret = uvc_query_ctrl(video->dev, GET_DEF, ctrl->entity->id, video->dev->intfnum, ctrl->info->selector, - &data, ctrl->info->size)) < 0) - return ret; + data, ctrl->info->size)) < 0) + goto out; v4l2_ctrl->default_value = uvc_get_le_value(data, mapping); } - if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) { + switch (mapping->v4l2_type) { + case V4L2_CTRL_TYPE_MENU: v4l2_ctrl->minimum = 0; v4l2_ctrl->maximum = mapping->menu_count - 1; v4l2_ctrl->step = 1; @@ -621,32 +627,46 @@ int uvc_query_v4l2_ctrl(struct uvc_video_device *video, } } - return 0; + ret = 0; + goto out; + + case V4L2_CTRL_TYPE_BOOLEAN: + v4l2_ctrl->minimum = 0; + v4l2_ctrl->maximum = 1; + v4l2_ctrl->step = 1; + ret = 0; + goto out; + + default: + break; } if (ctrl->info->flags & UVC_CONTROL_GET_MIN) { if ((ret = uvc_query_ctrl(video->dev, GET_MIN, ctrl->entity->id, video->dev->intfnum, ctrl->info->selector, - &data, ctrl->info->size)) < 0) - return ret; + data, ctrl->info->size)) < 0) + goto out; v4l2_ctrl->minimum = uvc_get_le_value(data, mapping); } if (ctrl->info->flags & UVC_CONTROL_GET_MAX) { if ((ret = uvc_query_ctrl(video->dev, GET_MAX, ctrl->entity->id, video->dev->intfnum, ctrl->info->selector, - &data, ctrl->info->size)) < 0) - return ret; + data, ctrl->info->size)) < 0) + goto out; v4l2_ctrl->maximum = uvc_get_le_value(data, mapping); } if (ctrl->info->flags & UVC_CONTROL_GET_RES) { if ((ret = uvc_query_ctrl(video->dev, GET_RES, ctrl->entity->id, video->dev->intfnum, ctrl->info->selector, - &data, ctrl->info->size)) < 0) - return ret; + data, ctrl->info->size)) < 0) + goto out; v4l2_ctrl->step = uvc_get_le_value(data, mapping); } - return 0; + ret = 0; +out: + kfree(data); + return ret; } diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index 79d6821c4..7e102034d 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -1459,8 +1459,6 @@ static int uvc_register_video(struct uvc_device *dev) * get another one. */ vdev->parent = &dev->intf->dev; - vdev->type = 0; - vdev->type2 = 0; vdev->minor = -1; vdev->fops = &uvc_fops; vdev->release = video_device_release; @@ -1886,7 +1884,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Packard Bell OEM Webcam */ + /* Packard Bell OEM Webcam - Bison Electronics */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x5986, @@ -1895,7 +1893,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Acer Crystal Eye webcam */ + /* Acer Crystal Eye webcam - Bison Electronics */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x5986, @@ -1904,7 +1902,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Medion Akoya Mini E1210 */ + /* Medion Akoya Mini E1210 - Bison Electronics */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x5986, @@ -1913,7 +1911,7 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, - /* Acer OrbiCam - Unknown vendor */ + /* Acer OrbiCam - Bison Electronics */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, .idVendor = 0x5986, @@ -1922,6 +1920,24 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* Bison Electronics */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x5986, + .idProduct = 0x0300, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* Clevo M570TU - Bison Electronics */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x5986, + .idProduct = 0x0303, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_PROBE_MINMAX }, /* Generic USB Video Class */ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, {} diff --git a/linux/drivers/media/video/uvc/uvc_queue.c b/linux/drivers/media/video/uvc/uvc_queue.c index 7388d0cee..5646a6a32 100644 --- a/linux/drivers/media/video/uvc/uvc_queue.c +++ b/linux/drivers/media/video/uvc/uvc_queue.c @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/version.h> +#include <linux/mm.h> #include <linux/list.h> #include <linux/module.h> #include <linux/usb.h> diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index ad63794fd..6854ac78a 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -90,17 +90,20 @@ static void uvc_fixup_buffer_size(struct uvc_video_device *video, static int uvc_get_video_ctrl(struct uvc_video_device *video, struct uvc_streaming_control *ctrl, int probe, __u8 query) { - __u8 data[34]; - __u8 size; + __u8 *data; + __u16 size; int ret; size = video->dev->uvc_version >= 0x0110 ? 34 : 26; + data = kmalloc(size, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + ret = __uvc_query_ctrl(video->dev, query, 0, video->streaming->intfnum, - probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size, + probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size, UVC_CTRL_STREAMING_TIMEOUT); - if (ret < 0) - return ret; + goto out; ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]); ctrl->bFormatIndex = data[2]; @@ -136,17 +139,22 @@ static int uvc_get_video_ctrl(struct uvc_video_device *video, */ uvc_fixup_buffer_size(video, ctrl); - return 0; +out: + kfree(data); + return ret; } int uvc_set_video_ctrl(struct uvc_video_device *video, struct uvc_streaming_control *ctrl, int probe) { - __u8 data[34]; - __u8 size; + __u8 *data; + __u16 size; + int ret; size = video->dev->uvc_version >= 0x0110 ? 34 : 26; - memset(data, 0, sizeof data); + data = kzalloc(size, GFP_KERNEL); + if (data == NULL) + return -ENOMEM; *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint); data[2] = ctrl->bFormatIndex; @@ -174,10 +182,13 @@ int uvc_set_video_ctrl(struct uvc_video_device *video, data[33] = ctrl->bMaxVersion; } - return __uvc_query_ctrl(video->dev, SET_CUR, 0, + ret = __uvc_query_ctrl(video->dev, SET_CUR, 0, video->streaming->intfnum, - probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, &data, size, + probe ? VS_PROBE_CONTROL : VS_COMMIT_CONTROL, data, size, UVC_CTRL_STREAMING_TIMEOUT); + + kfree(data); + return ret; } int uvc_probe_video(struct uvc_video_device *video, diff --git a/linux/drivers/media/video/v4l2-common.c b/linux/drivers/media/video/v4l2-common.c index 1e795e928..b5baf8f7e 100644 --- a/linux/drivers/media/video/v4l2-common.c +++ b/linux/drivers/media/video/v4l2-common.c @@ -64,7 +64,7 @@ #include <linux/kmod.h> #endif -#include <linux/videodev.h> +#include <linux/videodev2.h> #include "compat.h" MODULE_AUTHOR("Bill Dirks, Justin Schoeman, Gerd Knorr"); @@ -188,9 +188,11 @@ const char **v4l2_ctrl_get_menu(u32 id) NULL }; static const char *mpeg_audio_encoding[] = { - "Layer I", - "Layer II", - "Layer III", + "MPEG-1/2 Layer I", + "MPEG-1/2 Layer II", + "MPEG-1/2 Layer III", + "MPEG-2/4 AAC", + "AC-3", NULL }; static const char *mpeg_audio_l1_bitrate[] = { @@ -244,6 +246,28 @@ const char **v4l2_ctrl_get_menu(u32 id) "320 kbps", NULL }; + static const char *mpeg_audio_ac3_bitrate[] = { + "32 kbps", + "40 kbps", + "48 kbps", + "56 kbps", + "64 kbps", + "80 kbps", + "96 kbps", + "112 kbps", + "128 kbps", + "160 kbps", + "192 kbps", + "224 kbps", + "256 kbps", + "320 kbps", + "384 kbps", + "448 kbps", + "512 kbps", + "576 kbps", + "640 kbps", + NULL + }; static const char *mpeg_audio_mode[] = { "Stereo", "Joint Stereo", @@ -272,6 +296,7 @@ const char **v4l2_ctrl_get_menu(u32 id) static const char *mpeg_video_encoding[] = { "MPEG-1", "MPEG-2", + "MPEG-4 AVC", NULL }; static const char *mpeg_video_aspect[] = { @@ -312,6 +337,8 @@ const char **v4l2_ctrl_get_menu(u32 id) return mpeg_audio_l2_bitrate; case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return mpeg_audio_l3_bitrate; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + return mpeg_audio_ac3_bitrate; case V4L2_CID_MPEG_AUDIO_MODE: return mpeg_audio_mode; case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: @@ -336,62 +363,73 @@ const char **v4l2_ctrl_get_menu(u32 id) } EXPORT_SYMBOL(v4l2_ctrl_get_menu); -/* Fill in a struct v4l2_queryctrl */ -int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def) +/* Return the control name. */ +const char *v4l2_ctrl_get_name(u32 id) { - const char *name; - - qctrl->flags = 0; - switch (qctrl->id) { + switch (id) { /* USER controls */ - case V4L2_CID_USER_CLASS: name = "User Controls"; break; - case V4L2_CID_AUDIO_VOLUME: name = "Volume"; break; - case V4L2_CID_AUDIO_MUTE: name = "Mute"; break; - case V4L2_CID_AUDIO_BALANCE: name = "Balance"; break; - case V4L2_CID_AUDIO_BASS: name = "Bass"; break; - case V4L2_CID_AUDIO_TREBLE: name = "Treble"; break; - case V4L2_CID_AUDIO_LOUDNESS: name = "Loudness"; break; - case V4L2_CID_BRIGHTNESS: name = "Brightness"; break; - case V4L2_CID_CONTRAST: name = "Contrast"; break; - case V4L2_CID_SATURATION: name = "Saturation"; break; - case V4L2_CID_HUE: name = "Hue"; break; + case V4L2_CID_USER_CLASS: return "User Controls"; + case V4L2_CID_AUDIO_VOLUME: return "Volume"; + case V4L2_CID_AUDIO_MUTE: return "Mute"; + case V4L2_CID_AUDIO_BALANCE: return "Balance"; + case V4L2_CID_AUDIO_BASS: return "Bass"; + case V4L2_CID_AUDIO_TREBLE: return "Treble"; + case V4L2_CID_AUDIO_LOUDNESS: return "Loudness"; + case V4L2_CID_BRIGHTNESS: return "Brightness"; + case V4L2_CID_CONTRAST: return "Contrast"; + case V4L2_CID_SATURATION: return "Saturation"; + case V4L2_CID_HUE: return "Hue"; /* MPEG controls */ - case V4L2_CID_MPEG_CLASS: name = "MPEG Encoder Controls"; break; - case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: name = "Audio Sampling Frequency"; break; - case V4L2_CID_MPEG_AUDIO_ENCODING: name = "Audio Encoding Layer"; break; - case V4L2_CID_MPEG_AUDIO_L1_BITRATE: name = "Audio Layer I Bitrate"; break; - case V4L2_CID_MPEG_AUDIO_L2_BITRATE: name = "Audio Layer II Bitrate"; break; - case V4L2_CID_MPEG_AUDIO_L3_BITRATE: name = "Audio Layer III Bitrate"; break; - case V4L2_CID_MPEG_AUDIO_MODE: name = "Audio Stereo Mode"; break; - case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: name = "Audio Stereo Mode Extension"; break; - case V4L2_CID_MPEG_AUDIO_EMPHASIS: name = "Audio Emphasis"; break; - case V4L2_CID_MPEG_AUDIO_CRC: name = "Audio CRC"; break; - case V4L2_CID_MPEG_AUDIO_MUTE: name = "Audio Mute"; break; - case V4L2_CID_MPEG_VIDEO_ENCODING: name = "Video Encoding"; break; - case V4L2_CID_MPEG_VIDEO_ASPECT: name = "Video Aspect"; break; - case V4L2_CID_MPEG_VIDEO_B_FRAMES: name = "Video B Frames"; break; - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: name = "Video GOP Size"; break; - case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: name = "Video GOP Closure"; break; - case V4L2_CID_MPEG_VIDEO_PULLDOWN: name = "Video Pulldown"; break; - case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: name = "Video Bitrate Mode"; break; - case V4L2_CID_MPEG_VIDEO_BITRATE: name = "Video Bitrate"; break; - case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: name = "Video Peak Bitrate"; break; - case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: name = "Video Temporal Decimation"; break; - case V4L2_CID_MPEG_VIDEO_MUTE: name = "Video Mute"; break; - case V4L2_CID_MPEG_VIDEO_MUTE_YUV: name = "Video Mute YUV"; break; - case V4L2_CID_MPEG_STREAM_TYPE: name = "Stream Type"; break; - case V4L2_CID_MPEG_STREAM_PID_PMT: name = "Stream PMT Program ID"; break; - case V4L2_CID_MPEG_STREAM_PID_AUDIO: name = "Stream Audio Program ID"; break; - case V4L2_CID_MPEG_STREAM_PID_VIDEO: name = "Stream Video Program ID"; break; - case V4L2_CID_MPEG_STREAM_PID_PCR: name = "Stream PCR Program ID"; break; - case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: name = "Stream PES Audio ID"; break; - case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: name = "Stream PES Video ID"; break; - case V4L2_CID_MPEG_STREAM_VBI_FMT: name = "Stream VBI Format"; break; + case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls"; + case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency"; + case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding"; + case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate"; + case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate"; + case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate"; + case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate"; + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate"; + case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode"; + case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension"; + case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis"; + case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC"; + case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute"; + case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding"; + case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect"; + case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames"; + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size"; + case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure"; + case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown"; + case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode"; + case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate"; + case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate"; + case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation"; + case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute"; + case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV"; + case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type"; + case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID"; + case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID"; + case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID"; + case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID"; + case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio ID"; + case V4L2_CID_MPEG_STREAM_PES_ID_VIDEO: return "Stream PES Video ID"; + case V4L2_CID_MPEG_STREAM_VBI_FMT: return "Stream VBI Format"; default: - return -EINVAL; + return NULL; } +} +EXPORT_SYMBOL(v4l2_ctrl_get_name); + +/* Fill in a struct v4l2_queryctrl */ +int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def) +{ + const char *name = v4l2_ctrl_get_name(qctrl->id); + + qctrl->flags = 0; + if (name == NULL) + return -EINVAL; + switch (qctrl->id) { case V4L2_CID_AUDIO_MUTE: case V4L2_CID_AUDIO_LOUDNESS: @@ -408,6 +446,7 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 ste case V4L2_CID_MPEG_AUDIO_L1_BITRATE: case V4L2_CID_MPEG_AUDIO_L2_BITRATE: case V4L2_CID_MPEG_AUDIO_L3_BITRATE: + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: case V4L2_CID_MPEG_AUDIO_MODE: case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: case V4L2_CID_MPEG_AUDIO_EMPHASIS: @@ -494,7 +533,7 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) case V4L2_CID_MPEG_AUDIO_ENCODING: return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_AUDIO_ENCODING_LAYER_1, - V4L2_MPEG_AUDIO_ENCODING_LAYER_3, 1, + V4L2_MPEG_AUDIO_ENCODING_AC3, 1, V4L2_MPEG_AUDIO_ENCODING_LAYER_2); case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return v4l2_ctrl_query_fill(qctrl, @@ -511,6 +550,13 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) V4L2_MPEG_AUDIO_L3_BITRATE_32K, V4L2_MPEG_AUDIO_L3_BITRATE_320K, 1, V4L2_MPEG_AUDIO_L3_BITRATE_192K); + case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: + return v4l2_ctrl_query_fill(qctrl, 0, 6400, 1, 3200000); + case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: + return v4l2_ctrl_query_fill(qctrl, + V4L2_MPEG_AUDIO_AC3_BITRATE_32K, + V4L2_MPEG_AUDIO_AC3_BITRATE_640K, 1, + V4L2_MPEG_AUDIO_AC3_BITRATE_384K); case V4L2_CID_MPEG_AUDIO_MODE: return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_AUDIO_MODE_STEREO, @@ -536,7 +582,7 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) case V4L2_CID_MPEG_VIDEO_ENCODING: return v4l2_ctrl_query_fill(qctrl, V4L2_MPEG_VIDEO_ENCODING_MPEG_1, - V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1, + V4L2_MPEG_VIDEO_ENCODING_MPEG_4_AVC, 1, V4L2_MPEG_VIDEO_ENCODING_MPEG_2); case V4L2_CID_MPEG_VIDEO_ASPECT: return v4l2_ctrl_query_fill(qctrl, @@ -595,12 +641,17 @@ int v4l2_ctrl_query_fill_std(struct v4l2_queryctrl *qctrl) EXPORT_SYMBOL(v4l2_ctrl_query_fill_std); /* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and - the menu. The qctrl pointer may be NULL, in which case it is ignored. */ + the menu. The qctrl pointer may be NULL, in which case it is ignored. + If menu_items is NULL, then the menu items are retrieved using + v4l2_ctrl_get_menu. */ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl, const char **menu_items) { int i; + qmenu->reserved = 0; + if (menu_items == NULL) + menu_items = v4l2_ctrl_get_menu(qmenu->id); if (menu_items == NULL || (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum))) return -EINVAL; @@ -608,11 +659,31 @@ int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qc if (menu_items[i] == NULL || menu_items[i][0] == '\0') return -EINVAL; snprintf(qmenu->name, sizeof(qmenu->name), menu_items[qmenu->index]); - qmenu->reserved = 0; return 0; } EXPORT_SYMBOL(v4l2_ctrl_query_menu); +/* Fill in a struct v4l2_querymenu based on the specified array of valid + menu items (terminated by V4L2_CTRL_MENU_IDS_END). + Use this if there are 'holes' in the list of valid menu items. */ +int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids) +{ + const char **menu_items = v4l2_ctrl_get_menu(qmenu->id); + + qmenu->reserved = 0; + if (menu_items == NULL || ids == NULL) + return -EINVAL; + while (*ids != V4L2_CTRL_MENU_IDS_END) { + if (*ids++ == qmenu->index) { + snprintf(qmenu->name, sizeof(qmenu->name), + menu_items[qmenu->index]); + return 0; + } + } + return -EINVAL; +} +EXPORT_SYMBOL(v4l2_ctrl_query_menu_valid_items); + /* ctrl_classes points to an array of u32 pointers, the last element is a NULL pointer. Each u32 array is a 0-terminated array of control IDs. Each array must be sorted low to high and belong to the same control diff --git a/linux/drivers/media/video/v4l2-dev.c b/linux/drivers/media/video/v4l2-dev.c index 279f436fe..594f2477f 100644 --- a/linux/drivers/media/video/v4l2-dev.c +++ b/linux/drivers/media/video/v4l2-dev.c @@ -150,7 +150,6 @@ static int video_open(struct inode *inode, struct file *file) if (minor >= VIDEO_NUM_DEVICES) return -ENODEV; - lock_kernel(); mutex_lock(&videodev_lock); vfl = video_device[minor]; if (vfl == NULL) { @@ -160,7 +159,6 @@ static int video_open(struct inode *inode, struct file *file) vfl = video_device[minor]; if (vfl == NULL) { mutex_unlock(&videodev_lock); - unlock_kernel(); return -ENODEV; } } @@ -178,7 +176,6 @@ static int video_open(struct inode *inode, struct file *file) } fops_put(old_fops); mutex_unlock(&videodev_lock); - unlock_kernel(); return err; } @@ -260,11 +257,13 @@ int video_register_device(struct video_device *vfd, int type, int nr) EXPORT_SYMBOL(video_register_device); /** - * video_register_device - register video4linux devices + * video_register_device_index - register video4linux devices * @vfd: video device structure we want to register * @type: type of device to register * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... * -1 == first free) + * @index: stream number based on parent device; + * -1 if auto assign, requested number otherwise * * The registration code assigns minor numbers based on the type * requested. -ENFILE is returned in all the device slots for this @@ -317,7 +316,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, default: printk(KERN_ERR "%s called with unknown type: %d\n", __func__, type); - return -1; + return -EINVAL; } /* pick a minor number */ @@ -340,6 +339,7 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, } } video_device[i] = vfd; + vfd->vfl_type = type; vfd->minor = i; ret = get_index(vfd, index); @@ -356,10 +356,8 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, /* sysfs class */ memset(&vfd->dev, 0x00, sizeof(vfd->dev)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18) vfd->dev.class = &video_class; vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); -#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) if (vfd->parent) vfd->dev.dev = vfd->parent; diff --git a/linux/drivers/media/video/v4l2-ioctl.c b/linux/drivers/media/video/v4l2-ioctl.c index 61c244d87..51569f888 100644 --- a/linux/drivers/media/video/v4l2-ioctl.c +++ b/linux/drivers/media/video/v4l2-ioctl.c @@ -500,7 +500,7 @@ static void dbgbuf(unsigned int cmd, struct video_device *vfd, p->timestamp.tv_sec / 3600, (int)(p->timestamp.tv_sec / 60) % 60, (int)(p->timestamp.tv_sec % 60), - p->timestamp.tv_usec, + (long)p->timestamp.tv_usec, p->index, prt_names(p->type, v4l2_type_names), p->bytesused, p->flags, @@ -580,43 +580,46 @@ static inline int check_ext_ctrls(struct v4l2_ext_controls *c, int allow_priv) return 1; } -static int check_fmt(struct video_device *vfd, enum v4l2_buf_type type) +static int check_fmt(const struct v4l2_ioctl_ops *ops, enum v4l2_buf_type type) { + if (ops == NULL) + return -EINVAL; + switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_try_fmt_vid_cap) + if (ops->vidioc_try_fmt_vid_cap) return 0; break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_try_fmt_vid_overlay) + if (ops->vidioc_try_fmt_vid_overlay) return 0; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_try_fmt_vid_out) + if (ops->vidioc_try_fmt_vid_out) return 0; break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_try_fmt_vid_out_overlay) + if (ops->vidioc_try_fmt_vid_out_overlay) return 0; break; case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_vbi_cap) + if (ops->vidioc_try_fmt_vbi_cap) return 0; break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_vbi_out) + if (ops->vidioc_try_fmt_vbi_out) return 0; break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_sliced_vbi_cap) + if (ops->vidioc_try_fmt_sliced_vbi_cap) return 0; break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_sliced_vbi_out) + if (ops->vidioc_try_fmt_sliced_vbi_out) return 0; break; case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_try_fmt_type_private) + if (ops->vidioc_try_fmt_type_private) return 0; break; } @@ -627,6 +630,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { struct video_device *vfd = video_devdata(file); + const struct v4l2_ioctl_ops *ops = vfd->ioctl_ops; void *fh = file->private_data; int ret = -EINVAL; @@ -636,6 +640,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, printk(KERN_CONT "\n"); } + if (ops == NULL) { + printk(KERN_WARNING "videodev: \"%s\" has no ioctl_ops.\n", + vfd->name); + return -EINVAL; + } + #ifdef CONFIG_VIDEO_V4L1_COMPAT /*********************************************************** Handles calls to the obsoleted V4L1 API @@ -649,9 +659,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, memset(p, 0, sizeof(*p)); - if (!vfd->vidiocgmbuf) + if (!ops->vidiocgmbuf) return ret; - ret = vfd->vidiocgmbuf(file, fh, p); + ret = ops->vidiocgmbuf(file, fh, p); if (!ret) dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n", p->size, p->frames, @@ -665,7 +675,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, __video_do_ioctl will be called again, with one or more V4L2 ioctls. ********************************************************/ - if (_IOC_TYPE(cmd) == 'v') + if (_IOC_TYPE(cmd) == 'v' && _IOC_NR(cmd) < BASE_VIDIOCPRIVATE) return v4l_compat_translate_ioctl(inode, file, cmd, arg, __video_do_ioctl); #endif @@ -677,10 +687,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_capability *cap = (struct v4l2_capability *)arg; memset(cap, 0, sizeof(*cap)); - if (!vfd->vidioc_querycap) + if (!ops->vidioc_querycap) break; - ret = vfd->vidioc_querycap(file, fh, cap); + ret = ops->vidioc_querycap(file, fh, cap); if (!ret) dbgarg(cmd, "driver=%s, card=%s, bus=%s, " "version=0x%08x, " @@ -696,9 +706,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { enum v4l2_priority *p = arg; - if (!vfd->vidioc_g_priority) + if (!ops->vidioc_g_priority) break; - ret = vfd->vidioc_g_priority(file, fh, p); + ret = ops->vidioc_g_priority(file, fh, p); if (!ret) dbgarg(cmd, "priority is %d\n", *p); break; @@ -707,10 +717,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { enum v4l2_priority *p = arg; - if (!vfd->vidioc_s_priority) + if (!ops->vidioc_s_priority) break; dbgarg(cmd, "setting priority to %d\n", *p); - ret = vfd->vidioc_s_priority(file, fh, *p); + ret = ops->vidioc_s_priority(file, fh, *p); break; } @@ -729,12 +739,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_enum_fmt_vid_cap) - ret = vfd->vidioc_enum_fmt_vid_cap(file, fh, f); + if (ops->vidioc_enum_fmt_vid_cap) + ret = ops->vidioc_enum_fmt_vid_cap(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_enum_fmt_vid_overlay) - ret = vfd->vidioc_enum_fmt_vid_overlay(file, + if (ops->vidioc_enum_fmt_vid_overlay) + ret = ops->vidioc_enum_fmt_vid_overlay(file, fh, f); break; #if 1 /* keep */ @@ -743,19 +753,19 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, * it though, so just warn that this is deprecated and will be * removed in the near future. */ case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_enum_fmt_vbi_cap) { + if (ops->vidioc_enum_fmt_vbi_cap) { printk(KERN_WARNING "vidioc_enum_fmt_vbi_cap will be removed in 2.6.28!\n"); - ret = vfd->vidioc_enum_fmt_vbi_cap(file, fh, f); + ret = ops->vidioc_enum_fmt_vbi_cap(file, fh, f); } break; #endif case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_enum_fmt_vid_out) - ret = vfd->vidioc_enum_fmt_vid_out(file, fh, f); + if (ops->vidioc_enum_fmt_vid_out) + ret = ops->vidioc_enum_fmt_vid_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_enum_fmt_type_private) - ret = vfd->vidioc_enum_fmt_type_private(file, + if (ops->vidioc_enum_fmt_type_private) + ret = ops->vidioc_enum_fmt_type_private(file, fh, f); break; default: @@ -783,48 +793,48 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_g_fmt_vid_cap) - ret = vfd->vidioc_g_fmt_vid_cap(file, fh, f); + if (ops->vidioc_g_fmt_vid_cap) + ret = ops->vidioc_g_fmt_vid_cap(file, fh, f); if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_g_fmt_vid_overlay) - ret = vfd->vidioc_g_fmt_vid_overlay(file, + if (ops->vidioc_g_fmt_vid_overlay) + ret = ops->vidioc_g_fmt_vid_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_g_fmt_vid_out) - ret = vfd->vidioc_g_fmt_vid_out(file, fh, f); + if (ops->vidioc_g_fmt_vid_out) + ret = ops->vidioc_g_fmt_vid_out(file, fh, f); if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_g_fmt_vid_out_overlay) - ret = vfd->vidioc_g_fmt_vid_out_overlay(file, + if (ops->vidioc_g_fmt_vid_out_overlay) + ret = ops->vidioc_g_fmt_vid_out_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_g_fmt_vbi_cap) - ret = vfd->vidioc_g_fmt_vbi_cap(file, fh, f); + if (ops->vidioc_g_fmt_vbi_cap) + ret = ops->vidioc_g_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_g_fmt_vbi_out) - ret = vfd->vidioc_g_fmt_vbi_out(file, fh, f); + if (ops->vidioc_g_fmt_vbi_out) + ret = ops->vidioc_g_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_g_fmt_sliced_vbi_cap) - ret = vfd->vidioc_g_fmt_sliced_vbi_cap(file, + if (ops->vidioc_g_fmt_sliced_vbi_cap) + ret = ops->vidioc_g_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_g_fmt_sliced_vbi_out) - ret = vfd->vidioc_g_fmt_sliced_vbi_out(file, + if (ops->vidioc_g_fmt_sliced_vbi_out) + ret = ops->vidioc_g_fmt_sliced_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_g_fmt_type_private) - ret = vfd->vidioc_g_fmt_type_private(file, + if (ops->vidioc_g_fmt_type_private) + ret = ops->vidioc_g_fmt_type_private(file, fh, f); break; } @@ -841,45 +851,45 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (vfd->vidioc_s_fmt_vid_cap) - ret = vfd->vidioc_s_fmt_vid_cap(file, fh, f); + if (ops->vidioc_s_fmt_vid_cap) + ret = ops->vidioc_s_fmt_vid_cap(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_s_fmt_vid_overlay) - ret = vfd->vidioc_s_fmt_vid_overlay(file, + if (ops->vidioc_s_fmt_vid_overlay) + ret = ops->vidioc_s_fmt_vid_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: v4l_print_pix_fmt(vfd, &f->fmt.pix); - if (vfd->vidioc_s_fmt_vid_out) - ret = vfd->vidioc_s_fmt_vid_out(file, fh, f); + if (ops->vidioc_s_fmt_vid_out) + ret = ops->vidioc_s_fmt_vid_out(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_s_fmt_vid_out_overlay) - ret = vfd->vidioc_s_fmt_vid_out_overlay(file, + if (ops->vidioc_s_fmt_vid_out_overlay) + ret = ops->vidioc_s_fmt_vid_out_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_s_fmt_vbi_cap) - ret = vfd->vidioc_s_fmt_vbi_cap(file, fh, f); + if (ops->vidioc_s_fmt_vbi_cap) + ret = ops->vidioc_s_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_s_fmt_vbi_out) - ret = vfd->vidioc_s_fmt_vbi_out(file, fh, f); + if (ops->vidioc_s_fmt_vbi_out) + ret = ops->vidioc_s_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_s_fmt_sliced_vbi_cap) - ret = vfd->vidioc_s_fmt_sliced_vbi_cap(file, + if (ops->vidioc_s_fmt_sliced_vbi_cap) + ret = ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_s_fmt_sliced_vbi_out) - ret = vfd->vidioc_s_fmt_sliced_vbi_out(file, + if (ops->vidioc_s_fmt_sliced_vbi_out) + ret = ops->vidioc_s_fmt_sliced_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_s_fmt_type_private) - ret = vfd->vidioc_s_fmt_type_private(file, + if (ops->vidioc_s_fmt_type_private) + ret = ops->vidioc_s_fmt_type_private(file, fh, f); break; } @@ -894,48 +904,48 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, v4l2_type_names)); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (vfd->vidioc_try_fmt_vid_cap) - ret = vfd->vidioc_try_fmt_vid_cap(file, fh, f); + if (ops->vidioc_try_fmt_vid_cap) + ret = ops->vidioc_try_fmt_vid_cap(file, fh, f); if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OVERLAY: - if (vfd->vidioc_try_fmt_vid_overlay) - ret = vfd->vidioc_try_fmt_vid_overlay(file, + if (ops->vidioc_try_fmt_vid_overlay) + ret = ops->vidioc_try_fmt_vid_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (vfd->vidioc_try_fmt_vid_out) - ret = vfd->vidioc_try_fmt_vid_out(file, fh, f); + if (ops->vidioc_try_fmt_vid_out) + ret = ops->vidioc_try_fmt_vid_out(file, fh, f); if (!ret) v4l_print_pix_fmt(vfd, &f->fmt.pix); break; case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: - if (vfd->vidioc_try_fmt_vid_out_overlay) - ret = vfd->vidioc_try_fmt_vid_out_overlay(file, + if (ops->vidioc_try_fmt_vid_out_overlay) + ret = ops->vidioc_try_fmt_vid_out_overlay(file, fh, f); break; case V4L2_BUF_TYPE_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_vbi_cap) - ret = vfd->vidioc_try_fmt_vbi_cap(file, fh, f); + if (ops->vidioc_try_fmt_vbi_cap) + ret = ops->vidioc_try_fmt_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_vbi_out) - ret = vfd->vidioc_try_fmt_vbi_out(file, fh, f); + if (ops->vidioc_try_fmt_vbi_out) + ret = ops->vidioc_try_fmt_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: - if (vfd->vidioc_try_fmt_sliced_vbi_cap) - ret = vfd->vidioc_try_fmt_sliced_vbi_cap(file, + if (ops->vidioc_try_fmt_sliced_vbi_cap) + ret = ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, f); break; case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: - if (vfd->vidioc_try_fmt_sliced_vbi_out) - ret = vfd->vidioc_try_fmt_sliced_vbi_out(file, + if (ops->vidioc_try_fmt_sliced_vbi_out) + ret = ops->vidioc_try_fmt_sliced_vbi_out(file, fh, f); break; case V4L2_BUF_TYPE_PRIVATE: - if (vfd->vidioc_try_fmt_type_private) - ret = vfd->vidioc_try_fmt_type_private(file, + if (ops->vidioc_try_fmt_type_private) + ret = ops->vidioc_try_fmt_type_private(file, fh, f); break; } @@ -950,13 +960,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_requestbuffers *p = arg; - if (!vfd->vidioc_reqbufs) + if (!ops->vidioc_reqbufs) break; - ret = check_fmt(vfd, p->type); + ret = check_fmt(ops, p->type); if (ret) break; - ret = vfd->vidioc_reqbufs(file, fh, p); + ret = ops->vidioc_reqbufs(file, fh, p); dbgarg(cmd, "count=%d, type=%s, memory=%s\n", p->count, prt_names(p->type, v4l2_type_names), @@ -967,13 +977,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_buffer *p = arg; - if (!vfd->vidioc_querybuf) + if (!ops->vidioc_querybuf) break; - ret = check_fmt(vfd, p->type); + ret = check_fmt(ops, p->type); if (ret) break; - ret = vfd->vidioc_querybuf(file, fh, p); + ret = ops->vidioc_querybuf(file, fh, p); if (!ret) dbgbuf(cmd, vfd, p); break; @@ -982,13 +992,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_buffer *p = arg; - if (!vfd->vidioc_qbuf) + if (!ops->vidioc_qbuf) break; - ret = check_fmt(vfd, p->type); + ret = check_fmt(ops, p->type); if (ret) break; - ret = vfd->vidioc_qbuf(file, fh, p); + ret = ops->vidioc_qbuf(file, fh, p); if (!ret) dbgbuf(cmd, vfd, p); break; @@ -997,13 +1007,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_buffer *p = arg; - if (!vfd->vidioc_dqbuf) + if (!ops->vidioc_dqbuf) break; - ret = check_fmt(vfd, p->type); + ret = check_fmt(ops, p->type); if (ret) break; - ret = vfd->vidioc_dqbuf(file, fh, p); + ret = ops->vidioc_dqbuf(file, fh, p); if (!ret) dbgbuf(cmd, vfd, p); break; @@ -1012,19 +1022,19 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { int *i = arg; - if (!vfd->vidioc_overlay) + if (!ops->vidioc_overlay) break; dbgarg(cmd, "value=%d\n", *i); - ret = vfd->vidioc_overlay(file, fh, *i); + ret = ops->vidioc_overlay(file, fh, *i); break; } case VIDIOC_G_FBUF: { struct v4l2_framebuffer *p = arg; - if (!vfd->vidioc_g_fbuf) + if (!ops->vidioc_g_fbuf) break; - ret = vfd->vidioc_g_fbuf(file, fh, arg); + ret = ops->vidioc_g_fbuf(file, fh, arg); if (!ret) { dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", p->capability, p->flags, @@ -1037,32 +1047,32 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_framebuffer *p = arg; - if (!vfd->vidioc_s_fbuf) + if (!ops->vidioc_s_fbuf) break; dbgarg(cmd, "capability=0x%x, flags=%d, base=0x%08lx\n", p->capability, p->flags, (unsigned long)p->base); v4l_print_pix_fmt(vfd, &p->fmt); - ret = vfd->vidioc_s_fbuf(file, fh, arg); + ret = ops->vidioc_s_fbuf(file, fh, arg); break; } case VIDIOC_STREAMON: { enum v4l2_buf_type i = *(int *)arg; - if (!vfd->vidioc_streamon) + if (!ops->vidioc_streamon) break; dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); - ret = vfd->vidioc_streamon(file, fh, i); + ret = ops->vidioc_streamon(file, fh, i); break; } case VIDIOC_STREAMOFF: { enum v4l2_buf_type i = *(int *)arg; - if (!vfd->vidioc_streamoff) + if (!ops->vidioc_streamoff) break; dbgarg(cmd, "type=%s\n", prt_names(i, v4l2_type_names)); - ret = vfd->vidioc_streamoff(file, fh, i); + ret = ops->vidioc_streamoff(file, fh, i); break; } /* ---------- tv norms ---------- */ @@ -1111,8 +1121,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ret = 0; /* Calls the specific handler */ - if (vfd->vidioc_g_std) - ret = vfd->vidioc_g_std(file, fh, id); + if (ops->vidioc_g_std) + ret = ops->vidioc_g_std(file, fh, id); else *id = vfd->current_norm; @@ -1131,8 +1141,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, break; /* Calls the specific handler */ - if (vfd->vidioc_s_std) - ret = vfd->vidioc_s_std(file, fh, &norm); + if (ops->vidioc_s_std) + ret = ops->vidioc_s_std(file, fh, &norm); else ret = -EINVAL; @@ -1145,9 +1155,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { v4l2_std_id *p = arg; - if (!vfd->vidioc_querystd) + if (!ops->vidioc_querystd) break; - ret = vfd->vidioc_querystd(file, fh, arg); + ret = ops->vidioc_querystd(file, fh, arg); if (!ret) dbgarg(cmd, "detected std=%08Lx\n", (unsigned long long)*p); @@ -1160,12 +1170,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_input *p = arg; int i = p->index; - if (!vfd->vidioc_enum_input) + if (!ops->vidioc_enum_input) break; memset(p, 0, sizeof(*p)); p->index = i; - ret = vfd->vidioc_enum_input(file, fh, p); + ret = ops->vidioc_enum_input(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, type=%d, " "audioset=%d, " @@ -1180,9 +1190,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { unsigned int *i = arg; - if (!vfd->vidioc_g_input) + if (!ops->vidioc_g_input) break; - ret = vfd->vidioc_g_input(file, fh, i); + ret = ops->vidioc_g_input(file, fh, i); if (!ret) dbgarg(cmd, "value=%d\n", *i); break; @@ -1191,10 +1201,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { unsigned int *i = arg; - if (!vfd->vidioc_s_input) + if (!ops->vidioc_s_input) break; dbgarg(cmd, "value=%d\n", *i); - ret = vfd->vidioc_s_input(file, fh, *i); + ret = ops->vidioc_s_input(file, fh, *i); break; } @@ -1204,12 +1214,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_output *p = arg; int i = p->index; - if (!vfd->vidioc_enum_output) + if (!ops->vidioc_enum_output) break; memset(p, 0, sizeof(*p)); p->index = i; - ret = vfd->vidioc_enum_output(file, fh, p); + ret = ops->vidioc_enum_output(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, type=%d, " "audioset=0x%x, " @@ -1222,9 +1232,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { unsigned int *i = arg; - if (!vfd->vidioc_g_output) + if (!ops->vidioc_g_output) break; - ret = vfd->vidioc_g_output(file, fh, i); + ret = ops->vidioc_g_output(file, fh, i); if (!ret) dbgarg(cmd, "value=%d\n", *i); break; @@ -1233,10 +1243,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { unsigned int *i = arg; - if (!vfd->vidioc_s_output) + if (!ops->vidioc_s_output) break; dbgarg(cmd, "value=%d\n", *i); - ret = vfd->vidioc_s_output(file, fh, *i); + ret = ops->vidioc_s_output(file, fh, *i); break; } @@ -1245,9 +1255,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_queryctrl *p = arg; - if (!vfd->vidioc_queryctrl) + if (!ops->vidioc_queryctrl) break; - ret = vfd->vidioc_queryctrl(file, fh, p); + ret = ops->vidioc_queryctrl(file, fh, p); if (!ret) dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, " "step=%d, default=%d, flags=0x%08x\n", @@ -1262,9 +1272,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_control *p = arg; - if (vfd->vidioc_g_ctrl) - ret = vfd->vidioc_g_ctrl(file, fh, p); - else if (vfd->vidioc_g_ext_ctrls) { + if (ops->vidioc_g_ctrl) + ret = ops->vidioc_g_ctrl(file, fh, p); + else if (ops->vidioc_g_ext_ctrls) { struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; @@ -1274,7 +1284,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ctrl.id = p->id; ctrl.value = p->value; if (check_ext_ctrls(&ctrls, 1)) { - ret = vfd->vidioc_g_ext_ctrls(file, fh, &ctrls); + ret = ops->vidioc_g_ext_ctrls(file, fh, &ctrls); if (ret == 0) p->value = ctrl.value; } @@ -1292,16 +1302,16 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_ext_controls ctrls; struct v4l2_ext_control ctrl; - if (!vfd->vidioc_s_ctrl && !vfd->vidioc_s_ext_ctrls) + if (!ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls) break; dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value); - if (vfd->vidioc_s_ctrl) { - ret = vfd->vidioc_s_ctrl(file, fh, p); + if (ops->vidioc_s_ctrl) { + ret = ops->vidioc_s_ctrl(file, fh, p); break; } - if (!vfd->vidioc_s_ext_ctrls) + if (!ops->vidioc_s_ext_ctrls) break; ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(p->id); @@ -1310,7 +1320,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, ctrl.id = p->id; ctrl.value = p->value; if (check_ext_ctrls(&ctrls, 1)) - ret = vfd->vidioc_s_ext_ctrls(file, fh, &ctrls); + ret = ops->vidioc_s_ext_ctrls(file, fh, &ctrls); break; } case VIDIOC_G_EXT_CTRLS: @@ -1318,10 +1328,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_ext_controls *p = arg; p->error_idx = p->count; - if (!vfd->vidioc_g_ext_ctrls) + if (!ops->vidioc_g_ext_ctrls) break; if (check_ext_ctrls(p, 0)) - ret = vfd->vidioc_g_ext_ctrls(file, fh, p); + ret = ops->vidioc_g_ext_ctrls(file, fh, p); v4l_print_ext_ctrls(cmd, vfd, p, !ret); break; } @@ -1330,11 +1340,11 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_ext_controls *p = arg; p->error_idx = p->count; - if (!vfd->vidioc_s_ext_ctrls) + if (!ops->vidioc_s_ext_ctrls) break; v4l_print_ext_ctrls(cmd, vfd, p, 1); if (check_ext_ctrls(p, 0)) - ret = vfd->vidioc_s_ext_ctrls(file, fh, p); + ret = ops->vidioc_s_ext_ctrls(file, fh, p); break; } case VIDIOC_TRY_EXT_CTRLS: @@ -1342,20 +1352,20 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_ext_controls *p = arg; p->error_idx = p->count; - if (!vfd->vidioc_try_ext_ctrls) + if (!ops->vidioc_try_ext_ctrls) break; v4l_print_ext_ctrls(cmd, vfd, p, 1); if (check_ext_ctrls(p, 0)) - ret = vfd->vidioc_try_ext_ctrls(file, fh, p); + ret = ops->vidioc_try_ext_ctrls(file, fh, p); break; } case VIDIOC_QUERYMENU: { struct v4l2_querymenu *p = arg; - if (!vfd->vidioc_querymenu) + if (!ops->vidioc_querymenu) break; - ret = vfd->vidioc_querymenu(file, fh, p); + ret = ops->vidioc_querymenu(file, fh, p); if (!ret) dbgarg(cmd, "id=0x%x, index=%d, name=%s\n", p->id, p->index, p->name); @@ -1369,9 +1379,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_audio *p = arg; - if (!vfd->vidioc_enumaudio) + if (!ops->vidioc_enumaudio) break; - ret = vfd->vidioc_enumaudio(file, fh, p); + ret = ops->vidioc_enumaudio(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " "mode=0x%x\n", p->index, p->name, @@ -1385,12 +1395,12 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_audio *p = arg; __u32 index = p->index; - if (!vfd->vidioc_g_audio) + if (!ops->vidioc_g_audio) break; memset(p, 0, sizeof(*p)); p->index = index; - ret = vfd->vidioc_g_audio(file, fh, p); + ret = ops->vidioc_g_audio(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " "mode=0x%x\n", p->index, @@ -1403,22 +1413,22 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_audio *p = arg; - if (!vfd->vidioc_s_audio) + if (!ops->vidioc_s_audio) break; dbgarg(cmd, "index=%d, name=%s, capability=0x%x, " "mode=0x%x\n", p->index, p->name, p->capability, p->mode); - ret = vfd->vidioc_s_audio(file, fh, p); + ret = ops->vidioc_s_audio(file, fh, p); break; } case VIDIOC_ENUMAUDOUT: { struct v4l2_audioout *p = arg; - if (!vfd->vidioc_enumaudout) + if (!ops->vidioc_enumaudout) break; dbgarg(cmd, "Enum for index=%d\n", p->index); - ret = vfd->vidioc_enumaudout(file, fh, p); + ret = ops->vidioc_enumaudout(file, fh, p); if (!ret) dbgarg2("index=%d, name=%s, capability=%d, " "mode=%d\n", p->index, p->name, @@ -1429,10 +1439,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_audioout *p = arg; - if (!vfd->vidioc_g_audout) + if (!ops->vidioc_g_audout) break; dbgarg(cmd, "Enum for index=%d\n", p->index); - ret = vfd->vidioc_g_audout(file, fh, p); + ret = ops->vidioc_g_audout(file, fh, p); if (!ret) dbgarg2("index=%d, name=%s, capability=%d, " "mode=%d\n", p->index, p->name, @@ -1443,22 +1453,22 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_audioout *p = arg; - if (!vfd->vidioc_s_audout) + if (!ops->vidioc_s_audout) break; dbgarg(cmd, "index=%d, name=%s, capability=%d, " "mode=%d\n", p->index, p->name, p->capability, p->mode); - ret = vfd->vidioc_s_audout(file, fh, p); + ret = ops->vidioc_s_audout(file, fh, p); break; } case VIDIOC_G_MODULATOR: { struct v4l2_modulator *p = arg; - if (!vfd->vidioc_g_modulator) + if (!ops->vidioc_g_modulator) break; - ret = vfd->vidioc_g_modulator(file, fh, p); + ret = ops->vidioc_g_modulator(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, " "capability=%d, rangelow=%d," @@ -1472,23 +1482,23 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_modulator *p = arg; - if (!vfd->vidioc_s_modulator) + if (!ops->vidioc_s_modulator) break; dbgarg(cmd, "index=%d, name=%s, capability=%d, " "rangelow=%d, rangehigh=%d, txsubchans=%d\n", p->index, p->name, p->capability, p->rangelow, p->rangehigh, p->txsubchans); - ret = vfd->vidioc_s_modulator(file, fh, p); + ret = ops->vidioc_s_modulator(file, fh, p); break; } case VIDIOC_G_CROP: { struct v4l2_crop *p = arg; - if (!vfd->vidioc_g_crop) + if (!ops->vidioc_g_crop) break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = vfd->vidioc_g_crop(file, fh, p); + ret = ops->vidioc_g_crop(file, fh, p); if (!ret) dbgrect(vfd, "", &p->c); break; @@ -1497,11 +1507,11 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_crop *p = arg; - if (!vfd->vidioc_s_crop) + if (!ops->vidioc_s_crop) break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); dbgrect(vfd, "", &p->c); - ret = vfd->vidioc_s_crop(file, fh, p); + ret = ops->vidioc_s_crop(file, fh, p); break; } case VIDIOC_CROPCAP: @@ -1509,10 +1519,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_cropcap *p = arg; /*FIXME: Should also show v4l2_fract pixelaspect */ - if (!vfd->vidioc_cropcap) + if (!ops->vidioc_cropcap) break; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = vfd->vidioc_cropcap(file, fh, p); + ret = ops->vidioc_cropcap(file, fh, p); if (!ret) { dbgrect(vfd, "bounds ", &p->bounds); dbgrect(vfd, "defrect ", &p->defrect); @@ -1523,9 +1533,9 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_jpegcompression *p = arg; - if (!vfd->vidioc_g_jpegcomp) + if (!ops->vidioc_g_jpegcomp) break; - ret = vfd->vidioc_g_jpegcomp(file, fh, p); + ret = ops->vidioc_g_jpegcomp(file, fh, p); if (!ret) dbgarg(cmd, "quality=%d, APPn=%d, " "APP_len=%d, COM_len=%d, " @@ -1538,22 +1548,22 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_jpegcompression *p = arg; - if (!vfd->vidioc_g_jpegcomp) + if (!ops->vidioc_g_jpegcomp) break; dbgarg(cmd, "quality=%d, APPn=%d, APP_len=%d, " "COM_len=%d, jpeg_markers=%d\n", p->quality, p->APPn, p->APP_len, p->COM_len, p->jpeg_markers); - ret = vfd->vidioc_s_jpegcomp(file, fh, p); + ret = ops->vidioc_s_jpegcomp(file, fh, p); break; } case VIDIOC_G_ENC_INDEX: { struct v4l2_enc_idx *p = arg; - if (!vfd->vidioc_g_enc_index) + if (!ops->vidioc_g_enc_index) break; - ret = vfd->vidioc_g_enc_index(file, fh, p); + ret = ops->vidioc_g_enc_index(file, fh, p); if (!ret) dbgarg(cmd, "entries=%d, entries_cap=%d\n", p->entries, p->entries_cap); @@ -1563,10 +1573,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_encoder_cmd *p = arg; - if (!vfd->vidioc_encoder_cmd) + if (!ops->vidioc_encoder_cmd) break; memset(&p->raw, 0, sizeof(p->raw)); - ret = vfd->vidioc_encoder_cmd(file, fh, p); + ret = ops->vidioc_encoder_cmd(file, fh, p); if (!ret) dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); break; @@ -1575,10 +1585,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_encoder_cmd *p = arg; - if (!vfd->vidioc_try_encoder_cmd) + if (!ops->vidioc_try_encoder_cmd) break; memset(&p->raw, 0, sizeof(p->raw)); - ret = vfd->vidioc_try_encoder_cmd(file, fh, p); + ret = ops->vidioc_try_encoder_cmd(file, fh, p); if (!ret) dbgarg(cmd, "cmd=%d, flags=%x\n", p->cmd, p->flags); break; @@ -1591,8 +1601,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, memset(p, 0, sizeof(*p)); p->type = type; - if (vfd->vidioc_g_parm) { - ret = vfd->vidioc_g_parm(file, fh, p); + if (ops->vidioc_g_parm) { + ret = ops->vidioc_g_parm(file, fh, p); } else { struct v4l2_standard s; @@ -1613,10 +1623,10 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_streamparm *p = arg; - if (!vfd->vidioc_s_parm) + if (!ops->vidioc_s_parm) break; dbgarg(cmd, "type=%d\n", p->type); - ret = vfd->vidioc_s_parm(file, fh, p); + ret = ops->vidioc_s_parm(file, fh, p); break; } case VIDIOC_G_TUNER: @@ -1624,13 +1634,13 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_tuner *p = arg; __u32 index = p->index; - if (!vfd->vidioc_g_tuner) + if (!ops->vidioc_g_tuner) break; memset(p, 0, sizeof(*p)); p->index = index; - ret = vfd->vidioc_g_tuner(file, fh, p); + ret = ops->vidioc_g_tuner(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, type=%d, " "capability=0x%x, rangelow=%d, " @@ -1646,7 +1656,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_tuner *p = arg; - if (!vfd->vidioc_s_tuner) + if (!ops->vidioc_s_tuner) break; dbgarg(cmd, "index=%d, name=%s, type=%d, " "capability=0x%x, rangelow=%d, " @@ -1656,19 +1666,19 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, p->capability, p->rangelow, p->rangehigh, p->signal, p->afc, p->rxsubchans, p->audmode); - ret = vfd->vidioc_s_tuner(file, fh, p); + ret = ops->vidioc_s_tuner(file, fh, p); break; } case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *p = arg; - if (!vfd->vidioc_g_frequency) + if (!ops->vidioc_g_frequency) break; memset(p->reserved, 0, sizeof(p->reserved)); - ret = vfd->vidioc_g_frequency(file, fh, p); + ret = ops->vidioc_g_frequency(file, fh, p); if (!ret) dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", p->tuner, p->type, p->frequency); @@ -1678,11 +1688,11 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_frequency *p = arg; - if (!vfd->vidioc_s_frequency) + if (!ops->vidioc_s_frequency) break; dbgarg(cmd, "tuner=%d, type=%d, frequency=%d\n", p->tuner, p->type, p->frequency); - ret = vfd->vidioc_s_frequency(file, fh, p); + ret = ops->vidioc_s_frequency(file, fh, p); break; } case VIDIOC_G_SLICED_VBI_CAP: @@ -1690,21 +1700,21 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, struct v4l2_sliced_vbi_cap *p = arg; __u32 type = p->type; - if (!vfd->vidioc_g_sliced_vbi_cap) + if (!ops->vidioc_g_sliced_vbi_cap) break; memset(p, 0, sizeof(*p)); p->type = type; dbgarg(cmd, "type=%s\n", prt_names(p->type, v4l2_type_names)); - ret = vfd->vidioc_g_sliced_vbi_cap(file, fh, p); + ret = ops->vidioc_g_sliced_vbi_cap(file, fh, p); if (!ret) dbgarg2("service_set=%d\n", p->service_set); break; } case VIDIOC_LOG_STATUS: { - if (!vfd->vidioc_log_status) + if (!ops->vidioc_log_status) break; - ret = vfd->vidioc_log_status(file, fh); + ret = ops->vidioc_log_status(file, fh); break; } #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -1714,8 +1724,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (!capable(CAP_SYS_ADMIN)) ret = -EPERM; - else if (vfd->vidioc_g_register) - ret = vfd->vidioc_g_register(file, fh, p); + else if (ops->vidioc_g_register) + ret = ops->vidioc_g_register(file, fh, p); break; } case VIDIOC_DBG_S_REGISTER: @@ -1724,8 +1734,8 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, if (!capable(CAP_SYS_ADMIN)) ret = -EPERM; - else if (vfd->vidioc_s_register) - ret = vfd->vidioc_s_register(file, fh, p); + else if (ops->vidioc_s_register) + ret = ops->vidioc_s_register(file, fh, p); break; } #endif @@ -1733,30 +1743,30 @@ static int __video_do_ioctl(struct inode *inode, struct file *file, { struct v4l2_chip_ident *p = arg; - if (!vfd->vidioc_g_chip_ident) + if (!ops->vidioc_g_chip_ident) break; - ret = vfd->vidioc_g_chip_ident(file, fh, p); + ret = ops->vidioc_g_chip_ident(file, fh, p); if (!ret) dbgarg(cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); break; } - default: - { - if (!vfd->vidioc_default) - break; - ret = vfd->vidioc_default(file, fh, cmd, arg); - break; - } case VIDIOC_S_HW_FREQ_SEEK: { struct v4l2_hw_freq_seek *p = arg; - if (!vfd->vidioc_s_hw_freq_seek) + if (!ops->vidioc_s_hw_freq_seek) break; dbgarg(cmd, "tuner=%d, type=%d, seek_upward=%d, wrap_around=%d\n", p->tuner, p->type, p->seek_upward, p->wrap_around); - ret = vfd->vidioc_s_hw_freq_seek(file, fh, p); + ret = ops->vidioc_s_hw_freq_seek(file, fh, p); + break; + } + default: + { + if (!ops->vidioc_default) + break; + ret = ops->vidioc_default(file, fh, cmd, arg); break; } } /* switch */ diff --git a/linux/drivers/media/video/videobuf-core.c b/linux/drivers/media/video/videobuf-core.c index 16c32c68c..b104cd593 100644 --- a/linux/drivers/media/video/videobuf-core.c +++ b/linux/drivers/media/video/videobuf-core.c @@ -16,6 +16,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/moduleparam.h> +#include <linux/mm.h> #include <linux/slab.h> #include <linux/interrupt.h> diff --git a/linux/drivers/media/video/videobuf-vmalloc.c b/linux/drivers/media/video/videobuf-vmalloc.c index eb25cc257..e9cf83572 100644 --- a/linux/drivers/media/video/videobuf-vmalloc.c +++ b/linux/drivers/media/video/videobuf-vmalloc.c @@ -204,7 +204,7 @@ static int __videobuf_iolock (struct videobuf_queue* q, return 0; /* FIXME: to properly support USERPTR, remap should occur. - The code bellow won't work, since mem->vma = NULL + The code below won't work, since mem->vma = NULL */ /* Try to remap memory */ rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0); diff --git a/linux/drivers/media/video/vino.c b/linux/drivers/media/video/vino.c index 60527b164..9ada3fff2 100644 --- a/linux/drivers/media/video/vino.c +++ b/linux/drivers/media/video/vino.c @@ -38,8 +38,9 @@ #include <linux/i2c.h> #include <linux/i2c-algo-sgi.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <media/v4l2-common.h> +#include <media/v4l2-ioctl.h> #include <linux/video_decoder.h> #include <linux/mutex.h> @@ -4389,8 +4390,6 @@ static const struct file_operations vino_fops = { static struct video_device v4l_device_template = { .name = "NOT SET", - /*.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE | */ - /* VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY */ .fops = &vino_fops, .minor = -1, }; diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c index 7f4a53077..2f18381b6 100644 --- a/linux/drivers/media/video/vivi.c +++ b/linux/drivers/media/video/vivi.c @@ -901,9 +901,11 @@ static int vivi_open(struct inode *inode, struct file *file) printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor); + lock_kernel(); list_for_each_entry(dev, &vivi_devlist, vivi_devlist) if (dev->vfd->minor == minor) goto found; + unlock_kernel(); return -ENODEV; found: @@ -928,8 +930,10 @@ found: } unlock: mutex_unlock(&dev->mutex); - if (retval) + if (retval) { + unlock_kernel(); return retval; + } file->private_data = fh; fh->dev = dev; @@ -958,6 +962,7 @@ unlock: sizeof(struct vivi_buffer), fh); vivi_start_thread(fh); + unlock_kernel(); return 0; } @@ -1069,13 +1074,7 @@ static const struct file_operations vivi_fops = { .llseek = no_llseek, }; -static struct video_device vivi_template = { - .name = "vivi", - .type = VID_TYPE_CAPTURE, - .fops = &vivi_fops, - .minor = -1, - .release = video_device_release, - +static const struct v4l2_ioctl_ops vivi_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1097,6 +1096,15 @@ static struct video_device vivi_template = { #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf, #endif +}; + +static struct video_device vivi_template = { + .name = "vivi", + .fops = &vivi_fops, + .ioctl_ops = &vivi_ioctl_ops, + .minor = -1, + .release = video_device_release, + .tvnorms = V4L2_STD_525_60, .current_norm = V4L2_STD_NTSC_M, }; diff --git a/linux/drivers/media/video/vp27smpx.c b/linux/drivers/media/video/vp27smpx.c index 6c47c5e5a..80de9e796 100644 --- a/linux/drivers/media/video/vp27smpx.c +++ b/linux/drivers/media/video/vp27smpx.c @@ -27,7 +27,7 @@ #include <asm/uaccess.h> #include <linux/i2c.h> #include <linux/i2c-id.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-i2c-drv.h> diff --git a/linux/drivers/media/video/w9966.c b/linux/drivers/media/video/w9966.c index 66c730b8b..6aefc6566 100644 --- a/linux/drivers/media/video/w9966.c +++ b/linux/drivers/media/video/w9966.c @@ -58,7 +58,7 @@ #include <linux/init.h> #include <linux/delay.h> #include "compat.h" -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> #include <linux/parport.h> @@ -197,9 +197,7 @@ static const struct file_operations w9966_fops = { .llseek = no_llseek, }; static struct video_device w9966_template = { - .owner = THIS_MODULE, .name = W9966_DRIVERNAME, - .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, .fops = &w9966_fops, }; diff --git a/linux/drivers/media/video/w9968cf.c b/linux/drivers/media/video/w9968cf.c index 8e0f6bcfd..666438e8d 100644 --- a/linux/drivers/media/video/w9968cf.c +++ b/linux/drivers/media/video/w9968cf.c @@ -3558,8 +3558,6 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, symbolic(camlist, mod_id)); - cam->v4ldev->owner = THIS_MODULE; - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &w9968cf_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; diff --git a/linux/drivers/media/video/w9968cf.h b/linux/drivers/media/video/w9968cf.h index 15ea445e5..62c26b1ed 100644 --- a/linux/drivers/media/video/w9968cf.h +++ b/linux/drivers/media/video/w9968cf.h @@ -21,7 +21,7 @@ #ifndef _W9968CF_H_ #define _W9968CF_H_ -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <linux/usb.h> #include <linux/i2c.h> #include <linux/device.h> diff --git a/linux/drivers/media/video/wm8739.c b/linux/drivers/media/video/wm8739.c index b361d0d42..3ad19cf13 100644 --- a/linux/drivers/media/video/wm8739.c +++ b/linux/drivers/media/video/wm8739.c @@ -27,7 +27,7 @@ #include <asm/uaccess.h> #include <linux/i2c.h> #include <linux/i2c-id.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-i2c-drv.h> diff --git a/linux/drivers/media/video/wm8775.c b/linux/drivers/media/video/wm8775.c index e7a2e0449..ff7fa162b 100644 --- a/linux/drivers/media/video/wm8775.c +++ b/linux/drivers/media/video/wm8775.c @@ -31,7 +31,7 @@ #include <asm/uaccess.h> #include <linux/i2c.h> #include <linux/i2c-id.h> -#include <linux/videodev.h> +#include <linux/videodev2.h> #include <media/v4l2-common.h> #include <media/v4l2-chip-ident.h> #include <media/v4l2-i2c-drv-legacy.h> diff --git a/linux/drivers/media/video/zc0301/zc0301_core.c b/linux/drivers/media/video/zc0301/zc0301_core.c index e167fa560..e59145f65 100644 --- a/linux/drivers/media/video/zc0301/zc0301_core.c +++ b/linux/drivers/media/video/zc0301/zc0301_core.c @@ -1989,8 +1989,6 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) } strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera"); - cam->v4ldev->owner = THIS_MODULE; - cam->v4ldev->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; cam->v4ldev->fops = &zc0301_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; diff --git a/linux/drivers/media/video/zoran_card.c b/linux/drivers/media/video/zoran_card.c index cc45ae5cd..6678c6de9 100644 --- a/linux/drivers/media/video/zoran_card.c +++ b/linux/drivers/media/video/zoran_card.c @@ -162,7 +162,7 @@ static struct pci_device_id zr36067_pci_tbl[] = { MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); int zoran_num; /* number of Buzs in use */ -struct zoran zoran[BUZ_MAX]; +struct zoran *zoran[BUZ_MAX]; /* videocodec bus functions ZR36060 */ static u32 @@ -356,9 +356,15 @@ i2cid_to_modulename (u16 i2c_id) case I2C_DRIVERID_BT856: name = "bt856"; break; + case I2C_DRIVERID_BT866: + name = "bt866"; + break; case I2C_DRIVERID_VPX3220: name = "vpx3220"; break; + case I2C_DRIVERID_KS0127: + name = "ks0127"; + break; } return name; @@ -1165,7 +1171,7 @@ static void zoran_release (struct zoran *zr) { if (!zr->initialized) - return; + goto exit_free; /* unregister videocodec bus */ if (zr->codec) { struct videocodec_master *master = zr->codec->master_data; @@ -1193,6 +1199,8 @@ zoran_release (struct zoran *zr) iounmap(zr->zr36057_mem); pci_disable_device(zr->pci_dev); video_unregister_device(zr->video_dev); +exit_free: + kfree(zr); } void @@ -1270,8 +1278,14 @@ find_zr36057 (void) while (zoran_num < BUZ_MAX && (dev = pci_get_device(PCI_VENDOR_ID_ZORAN, PCI_DEVICE_ID_ZORAN_36057, dev)) != NULL) { card_num = card[zoran_num]; - zr = &zoran[zoran_num]; - memset(zr, 0, sizeof(struct zoran)); // Just in case if previous cycle failed + zr = kzalloc(sizeof(struct zoran), GFP_KERNEL); + if (!zr) { + dprintk(1, + KERN_ERR + "%s: find_zr36057() - kzalloc failed\n", + ZORAN_NAME); + continue; + } zr->pci_dev = dev; //zr->zr36057_mem = NULL; zr->id = zoran_num; @@ -1279,7 +1293,7 @@ find_zr36057 (void) spin_lock_init(&zr->spinlock); mutex_init(&zr->resource_lock); if (pci_enable_device(dev)) - continue; + goto zr_free_mem; zr->zr36057_adr = pci_resource_start(zr->pci_dev, 0); pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision); @@ -1295,7 +1309,7 @@ find_zr36057 (void) KERN_ERR "%s: find_zr36057() - no card specified, please use the card=X insmod option\n", ZR_DEVNAME(zr)); - continue; + goto zr_free_mem; } } else { int i; @@ -1334,7 +1348,7 @@ find_zr36057 (void) KERN_ERR "%s: find_zr36057() - unknown card\n", ZR_DEVNAME(zr)); - continue; + goto zr_free_mem; } } } @@ -1344,7 +1358,7 @@ find_zr36057 (void) KERN_ERR "%s: find_zr36057() - invalid cardnum %d\n", ZR_DEVNAME(zr), card_num); - continue; + goto zr_free_mem; } /* even though we make this a non pointer and thus @@ -1362,7 +1376,7 @@ find_zr36057 (void) KERN_ERR "%s: find_zr36057() - ioremap failed\n", ZR_DEVNAME(zr)); - continue; + goto zr_free_mem; } result = request_irq(zr->pci_dev->irq, @@ -1531,7 +1545,7 @@ find_zr36057 (void) } /* Success so keep the pci_dev referenced */ pci_dev_get(zr->pci_dev); - zoran_num++; + zoran[zoran_num++] = zr; continue; // Init errors @@ -1550,6 +1564,8 @@ find_zr36057 (void) free_irq(zr->pci_dev->irq, zr); zr_unmap: iounmap(zr->zr36057_mem); + zr_free_mem: + kfree(zr); continue; } if (dev) /* Clean up ref count on early exit */ @@ -1621,7 +1637,7 @@ init_dc10_cards (void) /* take care of Natoma chipset and a revision 1 zr36057 */ for (i = 0; i < zoran_num; i++) { - struct zoran *zr = &zoran[i]; + struct zoran *zr = zoran[i]; if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) { zr->jpg_buffers.need_contiguous = 1; @@ -1633,7 +1649,7 @@ init_dc10_cards (void) if (zr36057_init(zr) < 0) { for (i = 0; i < zoran_num; i++) - zoran_release(&zoran[i]); + zoran_release(zoran[i]); return -EIO; } zoran_proc_init(zr); @@ -1648,7 +1664,7 @@ unload_dc10_cards (void) int i; for (i = 0; i < zoran_num; i++) - zoran_release(&zoran[i]); + zoran_release(zoran[i]); } module_init(init_dc10_cards); diff --git a/linux/drivers/media/video/zoran_card.h b/linux/drivers/media/video/zoran_card.h index 1b5c4171c..e4dc9d29b 100644 --- a/linux/drivers/media/video/zoran_card.h +++ b/linux/drivers/media/video/zoran_card.h @@ -41,7 +41,7 @@ extern int zr36067_debug; /* Anybody who uses more than four? */ #define BUZ_MAX 4 extern int zoran_num; -extern struct zoran zoran[BUZ_MAX]; +extern struct zoran *zoran[BUZ_MAX]; extern struct video_device zoran_template; diff --git a/linux/drivers/media/video/zoran_driver.c b/linux/drivers/media/video/zoran_driver.c index 989a6f7e0..78e8430f4 100644 --- a/linux/drivers/media/video/zoran_driver.c +++ b/linux/drivers/media/video/zoran_driver.c @@ -1276,10 +1276,11 @@ zoran_open (struct inode *inode, struct zoran_fh *fh; int i, res, first_open = 0, have_module_locks = 0; + lock_kernel(); /* find the device */ for (i = 0; i < zoran_num; i++) { - if (zoran[i].video_dev->minor == minor) { - zr = &zoran[i]; + if (zoran[i]->video_dev->minor == minor) { + zr = zoran[i]; break; } } @@ -1386,6 +1387,7 @@ zoran_open (struct inode *inode, file->private_data = fh; fh->zr = zr; zoran_open_init_session(file); + unlock_kernel(); return 0; @@ -1403,6 +1405,7 @@ open_unlock_and_return: if (zr) { /*mutex_unlock(&zr->resource_lock);*/ } + unlock_kernel(); return res; } @@ -4709,8 +4712,6 @@ static const struct file_operations zoran_fops = { struct video_device zoran_template __devinitdata = { .name = ZORAN_NAME, - .type = ZORAN_VID_TYPE, - .type2 = ZORAN_V4L2_VID_FLAGS, .fops = &zoran_fops, .release = &zoran_vdev_release, .minor = -1 diff --git a/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c index 0967cdb3f..dbfdd6966 100644 --- a/linux/drivers/media/video/zr364xx.c +++ b/linux/drivers/media/video/zr364xx.c @@ -644,14 +644,18 @@ static int zr364xx_open(struct inode *inode, struct file *file) cam->skip = 2; + lock_kernel(); err = video_exclusive_open(inode, file); - if (err < 0) + if (err < 0) { + unlock_kernel(); return err; + } if (!cam->framebuf) { cam->framebuf = vmalloc_32(MAX_FRAME_SIZE * FRAMES); if (!cam->framebuf) { info("vmalloc_32 failed!"); + unlock_kernel(); return -ENOMEM; } } @@ -665,6 +669,7 @@ static int zr364xx_open(struct inode *inode, struct file *file) if (err < 0) { info("error during open sequence: %d", i); mutex_unlock(&cam->lock); + unlock_kernel(); return err; } } @@ -677,6 +682,7 @@ static int zr364xx_open(struct inode *inode, struct file *file) mdelay(100); mutex_unlock(&cam->lock); + unlock_kernel(); return 0; } @@ -763,14 +769,7 @@ static const struct file_operations zr364xx_fops = { .llseek = no_llseek, }; -static struct video_device zr364xx_template = { - .owner = THIS_MODULE, - .name = DRIVER_DESC, - .type = VID_TYPE_CAPTURE, - .fops = &zr364xx_fops, - .release = video_device_release, - .minor = -1, - +static const struct v4l2_ioctl_ops zr364xx_ioctl_ops = { .vidioc_querycap = zr364xx_vidioc_querycap, .vidioc_enum_fmt_vid_cap = zr364xx_vidioc_enum_fmt_vid_cap, .vidioc_try_fmt_vid_cap = zr364xx_vidioc_try_fmt_vid_cap, @@ -786,6 +785,14 @@ static struct video_device zr364xx_template = { .vidioc_s_ctrl = zr364xx_vidioc_s_ctrl, }; +static struct video_device zr364xx_template = { + .name = DRIVER_DESC, + .fops = &zr364xx_fops, + .ioctl_ops = &zr364xx_ioctl_ops, + .release = video_device_release, + .minor = -1, +}; + /*******************/ |