diff options
276 files changed, 6624 insertions, 3693 deletions
diff --git a/linux/Documentation/video4linux/CARDLIST.cx23885 b/linux/Documentation/video4linux/CARDLIST.cx23885 index bccafd357..64823ccac 100644 --- a/linux/Documentation/video4linux/CARDLIST.cx23885 +++ b/linux/Documentation/video4linux/CARDLIST.cx23885 @@ -10,3 +10,4 @@ 9 -> Hauppauge WinTV-HVR1400 [0070:8010] 10 -> DViCO FusionHDTV7 Dual Express [18ac:d618] 11 -> DViCO FusionHDTV DVB-T Dual Express [18ac:db78] + 12 -> Leadtek Winfast PxDVR3200 H [107d:6681] diff --git a/linux/Documentation/video4linux/gspca.txt b/linux/Documentation/video4linux/gspca.txt index 2dd2f774d..9a3e4d797 100644 --- a/linux/Documentation/video4linux/gspca.txt +++ b/linux/Documentation/video4linux/gspca.txt @@ -188,6 +188,9 @@ pac7311 093a:2608 Trust WB-3300p pac7311 093a:260e Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350 pac7311 093a:260f SnakeCam pac7311 093a:2621 PAC731x +pac7311 093a:2624 PAC7302 +pac7311 093a:2626 Labtec 2200 +pac7311 093a:262a Webcam 300k zc3xx 0ac8:0302 Z-star Vimicro zc0302 vc032x 0ac8:0321 Vimicro generic vc0321 vc032x 0ac8:0323 Vimicro Vc0323 diff --git a/linux/Documentation/video4linux/soc-camera.txt b/linux/Documentation/video4linux/soc-camera.txt new file mode 100644 index 000000000..178ef3c5e --- /dev/null +++ b/linux/Documentation/video4linux/soc-camera.txt @@ -0,0 +1,120 @@ + Soc-Camera Subsystem + ==================== + +Terminology +----------- + +The following terms are used in this document: + - camera / camera device / camera sensor - a video-camera sensor chip, capable + of connecting to a variety of systems and interfaces, typically uses i2c for + control and configuration, and a parallel or a serial bus for data. + - camera host - an interface, to which a camera is connected. Typically a + specialised interface, present on many SoCs, e.g., PXA27x and PXA3xx, SuperH, + AVR32, i.MX27, i.MX31. + - camera host bus - a connection between a camera host and a camera. Can be + parallel or serial, consists of data and control lines, e.g., clock, vertical + and horizontal synchronization signals. + +Purpose of the soc-camera subsystem +----------------------------------- + +The soc-camera subsystem provides a unified API between camera host drivers and +camera sensor drivers. It implements a V4L2 interface to the user, currently +only the mmap method is supported. + +This subsystem has been written to connect drivers for System-on-Chip (SoC) +video capture interfaces with drivers for CMOS camera sensor chips to enable +the reuse of sensor drivers with various hosts. The subsystem has been designed +to support multiple camera host interfaces and multiple cameras per interface, +although most applications have only one camera sensor. + +Existing drivers +---------------- + +As of 2.6.27-rc4 there are two host drivers in the mainline: pxa_camera.c for +PXA27x SoCs and sh_mobile_ceu_camera.c for SuperH SoCs, and four sensor drivers: +mt9m001.c, mt9m111.c, mt9v022.c and a generic soc_camera_platform.c driver. This +list is not supposed to be updated, look for more examples in your tree. + +Camera host API +--------------- + +A host camera driver is registered using the + +soc_camera_host_register(struct soc_camera_host *); + +function. The host object can be initialized as follows: + +static struct soc_camera_host pxa_soc_camera_host = { + .drv_name = PXA_CAM_DRV_NAME, + .ops = &pxa_soc_camera_host_ops, +}; + +All camera host methods are passed in a struct soc_camera_host_ops: + +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, + .reqbufs = pxa_camera_reqbufs, + .poll = pxa_camera_poll, + .querycap = pxa_camera_querycap, + .try_bus_param = pxa_camera_try_bus_param, + .set_bus_param = pxa_camera_set_bus_param, +}; + +.add and .remove methods are called when a sensor is attached to or detached +from the host, apart from performing host-internal tasks they shall also call +sensor driver's .init and .release methods respectively. .suspend and .resume +methods implement host's power-management functionality and its their +responsibility to call respective sensor's methods. .try_bus_param and +.set_bus_param are used to negotiate physical connection parameters between the +host and the sensor. .init_videobuf is called by soc-camera core when a +video-device is opened, further video-buffer management is implemented completely +by the specific camera host driver. The rest of the methods are called from +respective V4L2 operations. + +Camera API +---------- + +Sensor drivers can use struct soc_camera_link, typically provided by the +platform, and used to specify to which camera host bus the sensor is connected, +and arbitrarily provide platform .power and .reset methods for the camera. +soc_camera_device_register() and soc_camera_device_unregister() functions are +used to add a sensor driver to or remove one from the system. The registration +function takes a pointer to struct soc_camera_device as the only parameter. +This struct can be initialized as follows: + + /* link to driver operations */ + icd->ops = &mt9m001_ops; + /* link to the underlying physical (e.g., i2c) device */ + icd->control = &client->dev; + /* window geometry */ + icd->x_min = 20; + icd->y_min = 12; + icd->x_current = 20; + icd->y_current = 12; + icd->width_min = 48; + icd->width_max = 1280; + icd->height_min = 32; + icd->height_max = 1024; + icd->y_skip_top = 1; + /* camera bus ID, typically obtained from platform data */ + icd->iface = icl->bus_id; + +struct soc_camera_ops provides .probe and .remove methods, which are called by +the soc-camera core, when a camera is matched against or removed from a camera +host bus, .init, .release, .suspend, and .resume are called from the camera host +driver as discussed above. Other members of this struct provide respective V4L2 +functionality. + +struct soc_camera_device also links to an array of struct soc_camera_data_format, +listing pixel formats, supported by the camera. + +-- +Author: Guennadi Liakhovetski <g.liakhovetski@gmx.de> diff --git a/linux/arch/arm/mach-pxa/devices.c b/linux/arch/arm/mach-pxa/devices.c index 84489dc51..c77a4f753 100644 --- a/linux/arch/arm/mach-pxa/devices.c +++ b/linux/arch/arm/mach-pxa/devices.c @@ -4,6 +4,7 @@ #include <linux/platform_device.h> #include <linux/dma-mapping.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) #include <asm/arch/gpio.h> #include <asm/arch/udc.h> #include <asm/arch/pxafb.h> @@ -17,6 +18,21 @@ #include <asm/arch/camera.h> #include <asm/arch/audio.h> #include <asm/arch/pxa3xx_nand.h> +#else +#include <mach/gpio.h> +#include <mach/udc.h> +#include <mach/pxafb.h> +#include <mach/mmc.h> +#include <mach/irda.h> +#include <mach/i2c.h> +#include <mach/mfp-pxa27x.h> +#include <mach/ohci.h> +#include <mach/pxa27x_keypad.h> +#include <mach/pxa2xx_spi.h> +#include <mach/camera.h> +#include <mach/audio.h> +#include <mach/pxa3xx_nand.h> +#endif #include "devices.h" #include "generic.h" diff --git a/linux/arch/arm/mach-pxa/pcm990-baseboard.c b/linux/arch/arm/mach-pxa/pcm990-baseboard.c index 30023b00e..973370295 100644 --- a/linux/arch/arm/mach-pxa/pcm990-baseboard.c +++ b/linux/arch/arm/mach-pxa/pcm990-baseboard.c @@ -22,16 +22,24 @@ #include <linux/irq.h> #include <linux/platform_device.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) #include <linux/ide.h> +#endif #include <linux/i2c.h> #include <linux/pwm_backlight.h> #include <media/soc_camera.h> #include <asm/gpio.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) #include <asm/arch/i2c.h> #include <asm/arch/camera.h> +#else +#include <mach/i2c.h> +#include <mach/camera.h> +#endif #include <asm/mach/map.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) #include <asm/arch/pxa-regs.h> #include <asm/arch/audio.h> #include <asm/arch/mmc.h> @@ -39,6 +47,15 @@ #include <asm/arch/pcm990_baseboard.h> #include <asm/arch/pxafb.h> #include <asm/arch/mfp-pxa27x.h> +#else +#include <mach/pxa-regs.h> +#include <mach/audio.h> +#include <mach/mmc.h> +#include <mach/ohci.h> +#include <mach/pcm990_baseboard.h> +#include <mach/pxafb.h> +#include <mach/mfp-pxa27x.h> +#endif #include "devices.h" #include "generic.h" diff --git a/linux/drivers/media/common/saa7146_fops.c b/linux/drivers/media/common/saa7146_fops.c index a3dafa4fe..37a227d01 100644 --- a/linux/drivers/media/common/saa7146_fops.c +++ b/linux/drivers/media/common/saa7146_fops.c @@ -534,7 +534,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev, memcpy(vfd, &device_template, sizeof(struct video_device)); strlcpy(vfd->name, name, sizeof(vfd->name)); vfd->release = video_device_release; - vfd->priv = dev; + video_set_drvdata(vfd, dev); // fixme: -1 should be an insmod parameter *for the extension* (like "video_nr"); if (video_register_device(vfd, type, -1) < 0) { diff --git a/linux/drivers/media/common/saa7146_video.c b/linux/drivers/media/common/saa7146_video.c index 1c22c39c2..8804d4e78 100644 --- a/linux/drivers/media/common/saa7146_video.c +++ b/linux/drivers/media/common/saa7146_video.c @@ -1069,7 +1069,7 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int { v4l2_std_id *id = arg; int found = 0; - int i, err; + int i; DEB_EE(("VIDIOC_S_STD\n")); @@ -1117,7 +1117,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int case VIDIOC_OVERLAY: { int on = *(int *)arg; - int err = 0; DEB_D(("VIDIOC_OVERLAY on:%d\n",on)); if (on != 0) { @@ -1193,7 +1192,6 @@ int saa7146_video_do_ioctl(struct inode *inode, struct file *file, unsigned int case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; - struct videobuf_queue *q; int i; /* fixme: number of capture buffers and sizes for v4l apps */ diff --git a/linux/drivers/media/common/tuners/mt2131.c b/linux/drivers/media/common/tuners/mt2131.c index becc409d9..c528db6bb 100644 --- a/linux/drivers/media/common/tuners/mt2131.c +++ b/linux/drivers/media/common/tuners/mt2131.c @@ -1,7 +1,7 @@ /* * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/common/tuners/mt2131.h b/linux/drivers/media/common/tuners/mt2131.h index cd8376f6f..6632de640 100644 --- a/linux/drivers/media/common/tuners/mt2131.h +++ b/linux/drivers/media/common/tuners/mt2131.h @@ -1,7 +1,7 @@ /* * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/common/tuners/mt2131_priv.h b/linux/drivers/media/common/tuners/mt2131_priv.h index e930759c2..4e05a67e8 100644 --- a/linux/drivers/media/common/tuners/mt2131_priv.h +++ b/linux/drivers/media/common/tuners/mt2131_priv.h @@ -1,7 +1,7 @@ /* * Driver for Microtune MT2131 "QAM/8VSB single chip tuner" * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/common/tuners/mxl5005s.c b/linux/drivers/media/common/tuners/mxl5005s.c index e356db855..20405506a 100644 --- a/linux/drivers/media/common/tuners/mxl5005s.c +++ b/linux/drivers/media/common/tuners/mxl5005s.c @@ -2,7 +2,7 @@ MaxLinear MXL5005S VSB/QAM/DVBT tuner driver Copyright (C) 2008 MaxLinear - Copyright (C) 2006 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2006 Steven Toth <stoth@linuxtv.org> Functions: mxl5005s_reset() mxl5005s_writereg() @@ -3839,7 +3839,7 @@ static u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis) /* ---------------------------------------------------------------- * Begin: Everything after here is new code to adapt the * proprietary Realtek driver into a Linux API tuner. - * Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> */ static int mxl5005s_reset(struct dvb_frontend *fe) { diff --git a/linux/drivers/media/common/tuners/mxl5005s.h b/linux/drivers/media/common/tuners/mxl5005s.h index 396db150b..7ac6815b3 100644 --- a/linux/drivers/media/common/tuners/mxl5005s.h +++ b/linux/drivers/media/common/tuners/mxl5005s.h @@ -2,7 +2,7 @@ MaxLinear MXL5005S VSB/QAM/DVBT tuner driver Copyright (C) 2008 MaxLinear - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/common/tuners/tuner-simple.c b/linux/drivers/media/common/tuners/tuner-simple.c index a709d6bee..a379672cd 100644 --- a/linux/drivers/media/common/tuners/tuner-simple.c +++ b/linux/drivers/media/common/tuners/tuner-simple.c @@ -261,7 +261,7 @@ static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe, static int simple_config_lookup(struct dvb_frontend *fe, struct tuner_params *t_params, - int *frequency, u8 *config, u8 *cb) + unsigned *frequency, u8 *config, u8 *cb) { struct tuner_simple_priv *priv = fe->tuner_priv; int i; @@ -609,45 +609,45 @@ static int simple_set_tv_freq(struct dvb_frontend *fe, priv->last_div = div; if (t_params->has_tda9887) { struct v4l2_priv_tun_config tda9887_cfg; - int config = 0; + int tda_config = 0; int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) && !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)); tda9887_cfg.tuner = TUNER_TDA9887; - tda9887_cfg.priv = &config; + tda9887_cfg.priv = &tda_config; if (params->std == V4L2_STD_SECAM_LC) { if (t_params->port1_active ^ t_params->port1_invert_for_secam_lc) - config |= TDA9887_PORT1_ACTIVE; + tda_config |= TDA9887_PORT1_ACTIVE; if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc) - config |= TDA9887_PORT2_ACTIVE; + tda_config |= TDA9887_PORT2_ACTIVE; } else { if (t_params->port1_active) - config |= TDA9887_PORT1_ACTIVE; + tda_config |= TDA9887_PORT1_ACTIVE; if (t_params->port2_active) - config |= TDA9887_PORT2_ACTIVE; + tda_config |= TDA9887_PORT2_ACTIVE; } if (t_params->intercarrier_mode) - config |= TDA9887_INTERCARRIER; + tda_config |= TDA9887_INTERCARRIER; if (is_secam_l) { if (i == 0 && t_params->default_top_secam_low) - config |= TDA9887_TOP(t_params->default_top_secam_low); + tda_config |= TDA9887_TOP(t_params->default_top_secam_low); else if (i == 1 && t_params->default_top_secam_mid) - config |= TDA9887_TOP(t_params->default_top_secam_mid); + tda_config |= TDA9887_TOP(t_params->default_top_secam_mid); else if (t_params->default_top_secam_high) - config |= TDA9887_TOP(t_params->default_top_secam_high); + tda_config |= TDA9887_TOP(t_params->default_top_secam_high); } else { if (i == 0 && t_params->default_top_low) - config |= TDA9887_TOP(t_params->default_top_low); + tda_config |= TDA9887_TOP(t_params->default_top_low); else if (i == 1 && t_params->default_top_mid) - config |= TDA9887_TOP(t_params->default_top_mid); + tda_config |= TDA9887_TOP(t_params->default_top_mid); else if (t_params->default_top_high) - config |= TDA9887_TOP(t_params->default_top_high); + tda_config |= TDA9887_TOP(t_params->default_top_high); } if (t_params->default_pll_gating_18) - config |= TDA9887_GATING_18; + tda_config |= TDA9887_GATING_18; i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG, &tda9887_cfg); } @@ -835,7 +835,8 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, static struct tuner_params *t_params; u8 config, cb; u32 div; - int ret, frequency = params->frequency / 62500; + int ret; + unsigned frequency = params->frequency / 62500; t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL); ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb); diff --git a/linux/drivers/media/common/tuners/xc5000.c b/linux/drivers/media/common/tuners/xc5000.c index e0f045e1b..2c0a5b8d5 100644 --- a/linux/drivers/media/common/tuners/xc5000.c +++ b/linux/drivers/media/common/tuners/xc5000.c @@ -2,7 +2,7 @@ * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" * * Copyright (c) 2007 Xceive Corporation - * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/common/tuners/xc5000.h b/linux/drivers/media/common/tuners/xc5000.h index c910715ad..5389f7409 100644 --- a/linux/drivers/media/common/tuners/xc5000.h +++ b/linux/drivers/media/common/tuners/xc5000.h @@ -1,7 +1,7 @@ /* * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" * - * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/common/tuners/xc5000_priv.h b/linux/drivers/media/common/tuners/xc5000_priv.h index a72a9887f..b2a0074c9 100644 --- a/linux/drivers/media/common/tuners/xc5000_priv.h +++ b/linux/drivers/media/common/tuners/xc5000_priv.h @@ -1,7 +1,7 @@ /* * Driver for Xceive XC5000 "QAM/8VSB single chip tuner" * - * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index f9d087669..4eed783f4 100644 --- a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -137,7 +137,8 @@ static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, un flexcop_diseqc_send_byte(fe, 0xff); else { flexcop_set_tone(fe, SEC_TONE_ON); - udelay(12500); + mdelay(12); + udelay(500); flexcop_set_tone(fe, SEC_TONE_OFF); } msleep(20); diff --git a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c index 55973eaf3..43a112ec6 100644 --- a/linux/drivers/media/dvb/b2c2/flexcop-i2c.c +++ b/linux/drivers/media/dvb/b2c2/flexcop-i2c.c @@ -221,12 +221,12 @@ int flexcop_i2c_init(struct flexcop_device *fc) fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM; fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER; - strncpy(fc->fc_i2c_adap[0].i2c_adap.name, - "B2C2 FlexCop I2C to demod", I2C_NAME_SIZE); - strncpy(fc->fc_i2c_adap[1].i2c_adap.name, - "B2C2 FlexCop I2C to eeprom", I2C_NAME_SIZE); - strncpy(fc->fc_i2c_adap[2].i2c_adap.name, - "B2C2 FlexCop I2C to tuner", I2C_NAME_SIZE); + strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod", + sizeof(fc->fc_i2c_adap[0].i2c_adap.name)); + strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom", + sizeof(fc->fc_i2c_adap[1].i2c_adap.name)); + strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner", + sizeof(fc->fc_i2c_adap[2].i2c_adap.name)); i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]); i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]); diff --git a/linux/drivers/media/dvb/bt8xx/dst.c b/linux/drivers/media/dvb/bt8xx/dst.c index a7637562e..aa3db57d3 100644 --- a/linux/drivers/media/dvb/bt8xx/dst.c +++ b/linux/drivers/media/dvb/bt8xx/dst.c @@ -1244,7 +1244,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len) goto error; } if (state->type_flags & DST_TYPE_HAS_FW_1) - udelay(3000); + mdelay(3); if (read_dst(state, &reply, GET_ACK)) { dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); if ((dst_error_recovery(state)) < 0) { @@ -1260,7 +1260,7 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len) if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) goto error; if (state->type_flags & DST_TYPE_HAS_FW_1) - udelay(3000); + mdelay(3); else udelay(2000); if (!dst_wait_dst_ready(state, NO_DELAY)) diff --git a/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c index 5fb213cf9..c4b8b0677 100644 --- a/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/linux/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -703,7 +703,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) } if (card->fe == NULL) - printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + printk("dvb-bt8xx: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", card->bt->dev->vendor, card->bt->dev->device, card->bt->dev->subsystem_vendor, diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.c b/linux/drivers/media/dvb/dvb-core/dmxdev.c index 1cf9fcb6f..069d847ba 100644 --- a/linux/drivers/media/dvb/dvb-core/dmxdev.c +++ b/linux/drivers/media/dvb/dvb-core/dmxdev.c @@ -641,7 +641,6 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) struct timespec timeout = { 0 }; struct dmx_pes_filter_params *para = &filter->params.pes; dmx_output_t otype; - int ret; int ts_type; enum dmx_ts_pes ts_pes; struct dmx_ts_feed **tsfeed = &filter->feed.ts; diff --git a/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index c2954bf57..f6016feab 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1033,7 +1033,7 @@ static int dvb_ca_en50221_thread(void *data) /* we need this extra check for annoying interfaces like the budget-av */ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && (ca->pub->poll_slot_status)) { - int status = ca->pub->poll_slot_status(ca->pub, slot, 0); + status = ca->pub->poll_slot_status(ca->pub, slot, 0); if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; dvb_ca_en50221_thread_update_delay(ca); @@ -1090,7 +1090,7 @@ static int dvb_ca_en50221_thread(void *data) /* we need this extra check for annoying interfaces like the budget-av */ if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && (ca->pub->poll_slot_status)) { - int status = ca->pub->poll_slot_status(ca->pub, slot, 0); + status = ca->pub->poll_slot_status(ca->pub, slot, 0); if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; dvb_ca_en50221_thread_update_delay(ca); diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c index 8a9c2283f..60a94dc85 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -900,13 +900,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, * initialization, so parg is 8 bits and does not * include the initialization or start bit */ - unsigned long cmd = ((unsigned long) parg) << 1; + unsigned long swcmd = ((unsigned long) parg) << 1; struct timeval nexttime; struct timeval tv[10]; int i; u8 last = 1; if (dvb_frontend_debug) - printk("%s switch command: 0x%04lx\n", __func__, cmd); + printk("%s switch command: 0x%04lx\n", __func__, swcmd); do_gettimeofday(&nexttime); if (dvb_frontend_debug) memcpy(&tv[0], &nexttime, sizeof(struct timeval)); @@ -919,12 +919,12 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, for (i = 0; i < 9; i++) { if (dvb_frontend_debug) do_gettimeofday(&tv[i + 1]); - if ((cmd & 0x01) != last) { + if ((swcmd & 0x01) != last) { /* set voltage to (last ? 13V : 18V) */ fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); last = (last) ? 0 : 1; } - cmd = cmd >> 1; + swcmd = swcmd >> 1; if (i != 8) dvb_frontend_sleep_until(&nexttime, 8000); } diff --git a/linux/drivers/media/dvb/dvb-usb/af9005-remote.c b/linux/drivers/media/dvb/dvb-usb/af9005-remote.c index ff00c0e8f..7c596f926 100644 --- a/linux/drivers/media/dvb/dvb-usb/af9005-remote.c +++ b/linux/drivers/media/dvb/dvb-usb/af9005-remote.c @@ -25,7 +25,7 @@ */ #include "af9005.h" /* debug */ -int dvb_usb_af9005_remote_debug; +static int dvb_usb_af9005_remote_debug; module_param_named(debug, dvb_usb_af9005_remote_debug, int, 0644); MODULE_PARM_DESC(debug, "enable (1) or disable (0) debug messages." diff --git a/linux/drivers/media/dvb/dvb-usb/af9005-script.h b/linux/drivers/media/dvb/dvb-usb/af9005-script.h index 6eeaae51b..4d6904542 100644 --- a/linux/drivers/media/dvb/dvb-usb/af9005-script.h +++ b/linux/drivers/media/dvb/dvb-usb/af9005-script.h @@ -14,7 +14,7 @@ typedef struct { u8 val; } RegDesc; -RegDesc script[] = { +static RegDesc script[] = { {0xa180, 0x0, 0x8, 0xa}, {0xa181, 0x0, 0x8, 0xd7}, {0xa182, 0x0, 0x8, 0xa3}, diff --git a/linux/drivers/media/dvb/dvb-usb/af9005.c b/linux/drivers/media/dvb/dvb-usb/af9005.c index cfe71feef..ca5a0a4d2 100644 --- a/linux/drivers/media/dvb/dvb-usb/af9005.c +++ b/linux/drivers/media/dvb/dvb-usb/af9005.c @@ -35,17 +35,17 @@ module_param_named(led, dvb_usb_af9005_led, bool, 0644); MODULE_PARM_DESC(led, "enable led (default: 1)."); /* eeprom dump */ -int dvb_usb_af9005_dump_eeprom = 0; +static int dvb_usb_af9005_dump_eeprom; module_param_named(dump_eeprom, dvb_usb_af9005_dump_eeprom, int, 0); MODULE_PARM_DESC(dump_eeprom, "dump contents of the eeprom."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); /* remote control decoder */ -int (*rc_decode) (struct dvb_usb_device * d, u8 * data, int len, u32 * event, - int *state); -void *rc_keys; -int *rc_keys_size; +static int (*rc_decode) (struct dvb_usb_device *d, u8 *data, int len, + u32 *event, int *state); +static void *rc_keys; +static int *rc_keys_size; u8 regmask[8] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; @@ -54,8 +54,8 @@ struct af9005_device_state { int led_state; }; -int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen, - u8 * rbuf, u16 rlen, int delay_ms) +static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, + u8 *rbuf, u16 rlen, int delay_ms) { int actlen, ret = -ENOMEM; @@ -98,12 +98,7 @@ int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 * wbuf, u16 wlen, return ret; } -int af9005_usb_generic_write(struct dvb_usb_device *d, u8 * buf, u16 len) -{ - return af9005_usb_generic_rw(d, buf, len, NULL, 0, 0); -} - -int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, +static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg, int readwrite, int type, u8 * values, int len) { struct af9005_device_state *st = d->priv; @@ -765,7 +760,7 @@ static int af9005_boot_packet(struct usb_device *udev, int type, u8 * reply) return 0; } -int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) +static int af9005_download_firmware(struct usb_device *udev, const struct firmware *fw) { int i, packets, ret, act_len; diff --git a/linux/drivers/media/dvb/dvb-usb/cxusb.c b/linux/drivers/media/dvb/dvb-usb/cxusb.c index 49985f992..bffb44380 100644 --- a/linux/drivers/media/dvb/dvb-usb/cxusb.c +++ b/linux/drivers/media/dvb/dvb-usb/cxusb.c @@ -232,7 +232,7 @@ static int cxusb_aver_power_ctrl(struct dvb_usb_device *d, int onoff) if (d->state == DVB_USB_STATE_INIT && usb_set_interface(d->udev, 0, 0) < 0) err("set interface failed"); - do; while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && + do {} while (!(ret = cxusb_ctrl_msg(d, CMD_POWER_ON, NULL, 0, NULL, 0)) && !(ret = cxusb_ctrl_msg(d, 0x15, NULL, 0, NULL, 0)) && !(ret = cxusb_ctrl_msg(d, 0x17, NULL, 0, NULL, 0)) && 0); if (!ret) { diff --git a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c index 3dd20bfbe..6c0e5c5f4 100644 --- a/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c +++ b/linux/drivers/media/dvb/dvb-usb/dib0700_devices.c @@ -1117,7 +1117,8 @@ struct usb_device_id dib0700_usb_id_table[] = { { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) }, { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) }, { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) }, - { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, +/* 35 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009) }, + { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_3) }, { 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table); @@ -1373,7 +1374,7 @@ struct dvb_usb_device_properties dib0700_devices[] = { } }, - .num_device_descs = 3, + .num_device_descs = 4, .devices = { { "DiBcom STK7070PD reference design", { &dib0700_usb_id_table[17], NULL }, @@ -1386,6 +1387,10 @@ struct dvb_usb_device_properties dib0700_devices[] = { { "Hauppauge Nova-TD Stick (52009)", { &dib0700_usb_id_table[35], NULL }, { NULL }, + }, + { "Hauppauge Nova-TD-500 (84xxx)", + { &dib0700_usb_id_table[36], NULL }, + { NULL }, } } }, { DIB0700_DEFAULT_DEVICE_PROPERTIES, 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 851070b86..81369b79e 100644 --- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -131,6 +131,7 @@ #define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301 #define USB_PID_HAUPPAUGE_NOVA_T_500 0x9941 #define USB_PID_HAUPPAUGE_NOVA_T_500_2 0x9950 +#define USB_PID_HAUPPAUGE_NOVA_T_500_3 0x8400 #define USB_PID_HAUPPAUGE_NOVA_T_STICK 0x7050 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_2 0x7060 #define USB_PID_HAUPPAUGE_NOVA_T_STICK_3 0x7070 diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig index 774f5c2a7..e2444f270 100644 --- a/linux/drivers/media/dvb/frontends/Kconfig +++ b/linux/drivers/media/dvb/frontends/Kconfig @@ -392,4 +392,10 @@ config DVB_LGS8GL5 help A DMB-TH tuner module. Say Y when you want to support this frontend. +comment "Tools to develop new frontends" + +config DVB_DUMMY_FE + tristate "Dummy frontend driver" + default n + endmenu diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile index 262eaa429..ca24618d5 100644 --- a/linux/drivers/media/dvb/frontends/Makefile +++ b/linux/drivers/media/dvb/frontends/Makefile @@ -49,3 +49,4 @@ obj-$(CONFIG_DVB_AU8522) += au8522.o obj-$(CONFIG_DVB_TDA10048) += tda10048.o obj-$(CONFIG_DVB_S5H1411) += s5h1411.o obj-$(CONFIG_DVB_LGS8GL5) += lgs8gl5.o +obj-$(CONFIG_DVB_DUMMY_FE) += dvb_dummy_fe.o diff --git a/linux/drivers/media/dvb/frontends/au8522.c b/linux/drivers/media/dvb/frontends/au8522.c index d946c8beb..78e270ee0 100644 --- a/linux/drivers/media/dvb/frontends/au8522.c +++ b/linux/drivers/media/dvb/frontends/au8522.c @@ -1,7 +1,7 @@ /* Auvitek AU8522 QAM/8VSB demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/dvb/frontends/au8522.h b/linux/drivers/media/dvb/frontends/au8522.h index afc9af26e..595915ade 100644 --- a/linux/drivers/media/dvb/frontends/au8522.h +++ b/linux/drivers/media/dvb/frontends/au8522.h @@ -1,7 +1,7 @@ /* Auvitek AU8522 QAM/8VSB demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/dvb/frontends/cx22702.c b/linux/drivers/media/dvb/frontends/cx22702.c index cc1db4e37..9430e03db 100644 --- a/linux/drivers/media/dvb/frontends/cx22702.c +++ b/linux/drivers/media/dvb/frontends/cx22702.c @@ -7,7 +7,7 @@ Copyright (C) 2001-2002 Convergence Integrated Media GmbH Holger Waechtler <holger@convergence.de> - Copyright (C) 2004 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2004 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/dvb/frontends/cx22702.h b/linux/drivers/media/dvb/frontends/cx22702.h index 8af766a31..b1e465c6c 100644 --- a/linux/drivers/media/dvb/frontends/cx22702.h +++ b/linux/drivers/media/dvb/frontends/cx22702.h @@ -7,7 +7,7 @@ Copyright (C) 2001-2002 Convergence Integrated Media GmbH Holger Waechtler <holger@convergence.de> - Copyright (C) 2004 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2004 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/dvb/frontends/cx24110.h b/linux/drivers/media/dvb/frontends/cx24110.h index 1792adb23..fdcceee91 100644 --- a/linux/drivers/media/dvb/frontends/cx24110.h +++ b/linux/drivers/media/dvb/frontends/cx24110.h @@ -33,12 +33,17 @@ struct cx24110_config u8 demod_address; }; -static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) { - int r = 0; - u8 buf[] = {(u8) (val>>24), (u8) (val>>16), (u8) (val>>8)}; +static inline int cx24110_pll_write(struct dvb_frontend *fe, u32 val) +{ + u8 buf[] = { + (u8)((val >> 24) & 0xff), + (u8)((val >> 16) & 0xff), + (u8)((val >> 8) & 0xff) + }; + if (fe->ops.write) - r = fe->ops.write(fe, buf, 3); - return r; + return fe->ops.write(fe, buf, 3); + return 0; } #if defined(CONFIG_DVB_CX24110) || (defined(CONFIG_DVB_CX24110_MODULE) && defined(MODULE)) diff --git a/linux/drivers/media/dvb/frontends/cx24123.c b/linux/drivers/media/dvb/frontends/cx24123.c index 83b6793de..970e4df08 100644 --- a/linux/drivers/media/dvb/frontends/cx24123.c +++ b/linux/drivers/media/dvb/frontends/cx24123.c @@ -1,7 +1,7 @@ /* * Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver * - * Copyright (C) 2005 Steven Toth <stoth@hauppauge.com> + * Copyright (C) 2005 Steven Toth <stoth@linuxtv.org> * * Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc> * @@ -1083,8 +1083,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, if (config->dont_use_pll) cx24123_repeater_mode(state, 1, 0); - strncpy(state->tuner_i2c_adapter.name, - "CX24123 tuner I2C bus", I2C_NAME_SIZE); + strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus", + sizeof(state->tuner_i2c_adapter.name)); state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL, state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo; state->tuner_i2c_adapter.algo_data = NULL; diff --git a/linux/drivers/media/dvb/frontends/cx24123.h b/linux/drivers/media/dvb/frontends/cx24123.h index 81ebc3d2f..cc6b411d6 100644 --- a/linux/drivers/media/dvb/frontends/cx24123.h +++ b/linux/drivers/media/dvb/frontends/cx24123.h @@ -1,7 +1,7 @@ /* Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver - Copyright (C) 2005 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2005 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/dvb/frontends/dib7000m.c b/linux/drivers/media/dvb/frontends/dib7000m.c index 188f6e853..e6968317d 100644 --- a/linux/drivers/media/dvb/frontends/dib7000m.c +++ b/linux/drivers/media/dvb/frontends/dib7000m.c @@ -1320,7 +1320,8 @@ struct i2c_adapter * dib7000m_get_i2c_master(struct dvb_frontend *demod, enum di } EXPORT_SYMBOL(dib7000m_get_i2c_master); -int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, struct dib7000m_config cfg[]) +static int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, + u8 default_addr, struct dib7000m_config cfg[]) { struct dib7000m_state st = { .i2c_adap = i2c }; int k = 0; diff --git a/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c b/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c index fed09dfb2..db8a937cc 100644 --- a/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/linux/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -75,9 +75,10 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { - 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); + 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); } return 0; @@ -131,7 +132,7 @@ error: static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; -struct dvb_frontend* dvb_dummy_fe_qpsk_attach() +struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) { struct dvb_dummy_fe_state* state = NULL; @@ -151,7 +152,7 @@ error: static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; -struct dvb_frontend* dvb_dummy_fe_qam_attach() +struct dvb_frontend *dvb_dummy_fe_qam_attach(void) { struct dvb_dummy_fe_state* state = NULL; diff --git a/linux/drivers/media/dvb/frontends/s5h1409.c b/linux/drivers/media/dvb/frontends/s5h1409.c index 5ddb2dca3..7500a1c53 100644 --- a/linux/drivers/media/dvb/frontends/s5h1409.c +++ b/linux/drivers/media/dvb/frontends/s5h1409.c @@ -1,7 +1,7 @@ /* Samsung S5H1409 VSB/QAM demodulator driver - Copyright (C) 2006 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2006 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -404,6 +404,7 @@ static int s5h1409_enable_modulation(struct dvb_frontend* fe, break; case QAM_64: case QAM_256: + case QAM_AUTO: dprintk("%s() QAM_AUTO (64/256)\n", __func__); if (state->if_freq != S5H1409_QAM_IF_FREQ) s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ); diff --git a/linux/drivers/media/dvb/frontends/s5h1409.h b/linux/drivers/media/dvb/frontends/s5h1409.h index 59f433596..d1a1d2eb8 100644 --- a/linux/drivers/media/dvb/frontends/s5h1409.h +++ b/linux/drivers/media/dvb/frontends/s5h1409.h @@ -1,7 +1,7 @@ /* Samsung S5H1409 VSB/QAM demodulator driver - Copyright (C) 2006 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2006 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/dvb/frontends/s5h1411.c b/linux/drivers/media/dvb/frontends/s5h1411.c index cff360ce1..2da1a3763 100644 --- a/linux/drivers/media/dvb/frontends/s5h1411.c +++ b/linux/drivers/media/dvb/frontends/s5h1411.c @@ -1,7 +1,7 @@ /* Samsung S5H1411 VSB/QAM demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -488,6 +488,7 @@ static int s5h1411_enable_modulation(struct dvb_frontend *fe, break; case QAM_64: case QAM_256: + case QAM_AUTO: dprintk("%s() QAM_AUTO (64/256)\n", __func__); s5h1411_set_if_freq(fe, state->config->qam_if); s5h1411_writereg(state, S5H1411_I2C_TOP_ADDR, 0x00, 0x0171); diff --git a/linux/drivers/media/dvb/frontends/s5h1411.h b/linux/drivers/media/dvb/frontends/s5h1411.h index 1855f64ed..7d542bc00 100644 --- a/linux/drivers/media/dvb/frontends/s5h1411.h +++ b/linux/drivers/media/dvb/frontends/s5h1411.h @@ -1,7 +1,7 @@ /* Samsung S5H1411 VSB/QAM demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/dvb/frontends/s5h1420.c b/linux/drivers/media/dvb/frontends/s5h1420.c index 996f37704..b768da972 100644 --- a/linux/drivers/media/dvb/frontends/s5h1420.c +++ b/linux/drivers/media/dvb/frontends/s5h1420.c @@ -946,7 +946,8 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, state->frontend.demodulator_priv = state; /* create tuner i2c adapter */ - strncpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", I2C_NAME_SIZE); + strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", + sizeof(state->tuner_i2c_adapter.name)); state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL, state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo; state->tuner_i2c_adapter.algo_data = NULL; diff --git a/linux/drivers/media/dvb/frontends/sp887x.c b/linux/drivers/media/dvb/frontends/sp887x.c index 4543609e1..559509ab4 100644 --- a/linux/drivers/media/dvb/frontends/sp887x.c +++ b/linux/drivers/media/dvb/frontends/sp887x.c @@ -337,7 +337,8 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { struct sp887x_state* state = fe->demodulator_priv; - int actual_freq, err; + unsigned actual_freq; + int err; u16 val, reg0xc05; if (p->u.ofdm.bandwidth != BANDWIDTH_8_MHZ && diff --git a/linux/drivers/media/dvb/frontends/tda10048.c b/linux/drivers/media/dvb/frontends/tda10048.c index 7c718e247..7a882faf5 100644 --- a/linux/drivers/media/dvb/frontends/tda10048.c +++ b/linux/drivers/media/dvb/frontends/tda10048.c @@ -1,7 +1,7 @@ /* NXP TDA10048HN DVB OFDM demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -303,7 +303,7 @@ static int tda10048_firmware_upload(struct dvb_frontend *fe) if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) { printk(KERN_ERR "%s: firmware incorrect size\n", __func__); - return -EIO; + ret = -EIO; } else { printk(KERN_INFO "%s: firmware uploading\n", __func__); diff --git a/linux/drivers/media/dvb/frontends/tda10048.h b/linux/drivers/media/dvb/frontends/tda10048.h index 2b5c78e62..0457b2460 100644 --- a/linux/drivers/media/dvb/frontends/tda10048.h +++ b/linux/drivers/media/dvb/frontends/tda10048.h @@ -1,7 +1,7 @@ /* NXP TDA10048HN DVB OFDM demodulator driver - Copyright (C) 2008 Steven Toth <stoth@hauppauge.com> + Copyright (C) 2008 Steven Toth <stoth@linuxtv.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/dvb/frontends/tdhd1.h b/linux/drivers/media/dvb/frontends/tdhd1.h new file mode 100644 index 000000000..51f170678 --- /dev/null +++ b/linux/drivers/media/dvb/frontends/tdhd1.h @@ -0,0 +1,73 @@ +/* + * tdhd1.h - ALPS TDHD1-204A tuner support + * + * Copyright (C) 2008 Oliver Endriss <o.endriss@gmx.de> + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * The project's page is at http://www.linuxtv.org + */ + +#ifndef TDHD1_H +#define TDHD1_H + +#include "tda1004x.h" + +static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name); + +static struct tda1004x_config alps_tdhd1_204a_config = { + .demod_address = 0x8, + .invert = 1, + .invert_oclk = 0, + .xtal_freq = TDA10046_XTAL_4M, + .agc_config = TDA10046_AGC_DEFAULT, + .if_freq = TDA10046_FREQ_3617, + .request_firmware = alps_tdhd1_204_request_firmware +}; + +static int alps_tdhd1_204a_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct i2c_adapter *i2c = fe->tuner_priv; + u8 data[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + u32 div; + + div = (params->frequency + 36166666) / 166666; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = 0x85; + + if (params->frequency >= 174000000 && params->frequency <= 230000000) + data[3] = 0x02; + else if (params->frequency >= 470000000 && params->frequency <= 823000000) + data[3] = 0x0C; + else if (params->frequency > 823000000 && params->frequency <= 862000000) + data[3] = 0x8C; + else + return -EINVAL; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(i2c, &msg, 1) != 1) + return -EIO; + + return 0; +} + +#endif /* TDHD1_H */ diff --git a/linux/drivers/media/dvb/ttpci/Kconfig b/linux/drivers/media/dvb/ttpci/Kconfig index 41b5a988b..867027cea 100644 --- a/linux/drivers/media/dvb/ttpci/Kconfig +++ b/linux/drivers/media/dvb/ttpci/Kconfig @@ -86,6 +86,7 @@ config DVB_BUDGET select DVB_TDA10086 if !DVB_FE_CUSTOMISE select DVB_TDA826X if !DVB_FE_CUSTOMISE select DVB_LNBP21 if !DVB_FE_CUSTOMISE + select DVB_TDA1004X if !DVB_FE_CUSTOMISE help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard MPEG2 decoder, and without diff --git a/linux/drivers/media/dvb/ttpci/av7110.c b/linux/drivers/media/dvb/ttpci/av7110.c index 0909eb861..bb63e2121 100644 --- a/linux/drivers/media/dvb/ttpci/av7110.c +++ b/linux/drivers/media/dvb/ttpci/av7110.c @@ -88,6 +88,7 @@ static int budgetpatch; static int wss_cfg_4_3 = 0x4008; static int wss_cfg_16_9 = 0x0007; static int tv_standard; +static int full_ts; module_param_named(debug, av7110_debug, int, 0644); MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)"); @@ -106,6 +107,8 @@ module_param(volume, int, 0444); MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); module_param(budgetpatch, int, 0444); MODULE_PARM_DESC(budgetpatch, "use budget-patch hardware modification: default 0 (0 no, 1 autodetect, 2 always)"); +module_param(full_ts, int, 0444); +MODULE_PARM_DESC(full_ts, "enable code for full-ts hardware modification: 0 disable (default), 1 enable"); module_param(wss_cfg_4_3, int, 0444); MODULE_PARM_DESC(wss_cfg_4_3, "WSS 4:3 - default 0x4008 - bit 15: disable, 14: burst mode, 13..0: wss data"); module_param(wss_cfg_16_9, int, 0444); @@ -116,6 +119,8 @@ MODULE_PARM_DESC(tv_standard, "TV standard: 0 PAL (default), 1 NTSC"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); static void restart_feeds(struct av7110 *av7110); +static int budget_start_feed(struct dvb_demux_feed *feed); +static int budget_stop_feed(struct dvb_demux_feed *feed); static int av7110_num; @@ -376,9 +381,9 @@ static inline void start_debi_dma(struct av7110 *av7110, int dir, irdebi(av7110, DEBISWAB, addr, 0, len); } -static void debiirq(unsigned long data) +static void debiirq(unsigned long cookie) { - struct av7110 *av7110 = (struct av7110 *) data; + struct av7110 *av7110 = (struct av7110 *)cookie; int type = av7110->debitype; int handle = (type >> 8) & 0x1f; unsigned int xfer = 0; @@ -487,9 +492,9 @@ debi_done: } /* irq from av7110 firmware writing the mailbox register in the DPRAM */ -static void gpioirq(unsigned long data) +static void gpioirq(unsigned long cookie) { - struct av7110 *av7110 = (struct av7110 *) data; + struct av7110 *av7110 = (struct av7110 *)cookie; u32 rxbuf, txbuf; int len; @@ -806,6 +811,9 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) dprintk(4, "%p\n", av7110); + if (av7110->full_ts) + return 0; + if (dvbdmxfilter->type == DMX_TYPE_SEC) { if (hw_sections) { buf[4] = (dvbdmxfilter->filter.filter_value[0] << 8) | @@ -854,6 +862,9 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) dprintk(4, "%p\n", av7110); + if (av7110->full_ts) + return 0; + handle = dvbdmxfilter->hw_handle; if (handle >= 32) { printk("%s tried to stop invalid filter %04x, filter type = %x\n", @@ -913,7 +924,7 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed) return ret; } - if ((dvbdmxfeed->ts_type & TS_PACKET)) { + if ((dvbdmxfeed->ts_type & TS_PACKET) && !av7110->full_ts) { if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000)) ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed); if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000)) @@ -974,7 +985,7 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) if (!demux->dmx.frontend) return -EINVAL; - if (feed->pid > 0x1fff) + if (!av7110->full_ts && feed->pid > 0x1fff) return -EINVAL; if (feed->type == DMX_TYPE_TS) { @@ -1003,7 +1014,12 @@ static int av7110_start_feed(struct dvb_demux_feed *feed) } } - else if (feed->type == DMX_TYPE_SEC) { + if (av7110->full_ts) { + budget_start_feed(feed); + return ret; + } + + if (feed->type == DMX_TYPE_SEC) { int i; for (i = 0; i < demux->filternum; i++) { @@ -1050,7 +1066,12 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed) ret = StopHWFilter(feed->filter); } - if (!ret && feed->type == DMX_TYPE_SEC) { + if (av7110->full_ts) { + budget_stop_feed(feed); + return ret; + } + + if (feed->type == DMX_TYPE_SEC) { for (i = 0; i<demux->filternum; i++) { if (demux->filter[i].state == DMX_STATE_GO && demux->filter[i].filter.parent == &feed->feed.sec) { @@ -1074,6 +1095,7 @@ static void restart_feeds(struct av7110 *av7110) struct dvb_demux *dvbdmx = &av7110->demux; struct dvb_demux_feed *feed; int mode; + int feeding; int i, j; dprintk(4, "%p\n", av7110); @@ -1082,6 +1104,8 @@ static void restart_feeds(struct av7110 *av7110) av7110->playing = 0; av7110->rec_mode = 0; + feeding = av7110->feeding1; /* full_ts mod */ + for (i = 0; i < dvbdmx->feednum; i++) { feed = &dvbdmx->feed[i]; if (feed->state == DMX_STATE_GO) { @@ -1099,6 +1123,8 @@ static void restart_feeds(struct av7110 *av7110) } } + av7110->feeding1 = feeding; /* full_ts mod */ + if (mode) av7110_av_start_play(av7110, mode); } @@ -1197,8 +1223,9 @@ static int start_ts_capture(struct av7110 *budget) if (budget->feeding1) return ++budget->feeding1; - memset(budget->grabbing, 0x00, TS_HEIGHT * TS_WIDTH); + memset(budget->grabbing, 0x00, TS_BUFLEN); budget->ttbp = 0; + SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */ SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */ saa7146_write(budget->dev, MC1, (MASK_04 | MASK_20)); /* DMA3 on */ return ++budget->feeding1; @@ -1233,18 +1260,14 @@ static int budget_stop_feed(struct dvb_demux_feed *feed) return status; } -static void vpeirq(unsigned long data) +static void vpeirq(unsigned long cookie) { - struct av7110 *budget = (struct av7110 *) data; + struct av7110 *budget = (struct av7110 *)cookie; u8 *mem = (u8 *) (budget->grabbing); u32 olddma = budget->ttbp; u32 newdma = saa7146_read(budget->dev, PCI_VDP3); + struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1; - if (!budgetpatch) { - printk("av7110.c: vpeirq() called while budgetpatch disabled!" - " check saa7146 IER register\n"); - BUG(); - } /* nearest lower position divisible by 188 */ newdma -= newdma % 188; @@ -1268,11 +1291,11 @@ static void vpeirq(unsigned long data) if (newdma > olddma) /* no wraparound, dump olddma..newdma */ - dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (newdma - olddma) / 188); + dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188); else { /* wraparound, dump olddma..buflen and 0..newdma */ - dvb_dmx_swfilter_packets(&budget->demux1, mem + olddma, (TS_BUFLEN - olddma) / 188); - dvb_dmx_swfilter_packets(&budget->demux1, mem, newdma / 188); + dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188); + dvb_dmx_swfilter_packets(demux, mem, newdma / 188); } } @@ -1294,8 +1317,8 @@ static int av7110_register(struct av7110 *av7110) for (i = 0; i < 32; i++) av7110->handle2filter[i] = NULL; - dvbdemux->filternum = 32; - dvbdemux->feednum = 32; + dvbdemux->filternum = (av7110->full_ts) ? 256 : 32; + dvbdemux->feednum = (av7110->full_ts) ? 256 : 32; dvbdemux->start_feed = av7110_start_feed; dvbdemux->stop_feed = av7110_stop_feed; dvbdemux->write_to_decoder = av7110_write_to_decoder; @@ -1305,7 +1328,7 @@ static int av7110_register(struct av7110 *av7110) dvb_dmx_init(&av7110->demux); av7110->demux.dmx.get_stc = dvb_get_stc; - av7110->dmxdev.filternum = 32; + av7110->dmxdev.filternum = (av7110->full_ts) ? 256 : 32; av7110->dmxdev.demux = &dvbdemux->dmx; av7110->dmxdev.capabilities = 0; @@ -1422,7 +1445,6 @@ int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val) return i2c_transfer(&av7110->i2c_adap, &msgs, 1); } -#if 0 /* keep */ u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) { u8 mm1[] = {0x00}; @@ -1439,7 +1461,6 @@ u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg) return mm2[0]; } -#endif /**************************************************************************** * INITIALIZATION @@ -2256,7 +2277,7 @@ static int frontend_init(struct av7110 *av7110) if (!av7110->fe) { /* FIXME: propagate the failure code from the lower layers */ ret = -ENOMEM; - printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", av7110->dev->pci->vendor, av7110->dev->pci->device, av7110->dev->pci->subsystem_vendor, @@ -2484,7 +2505,47 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, av7110->dvb_adapter.proposed_mac); ret = -ENOMEM; - if (budgetpatch) { + /* full-ts mod? */ + if (full_ts) + av7110->full_ts = true; + + /* check for full-ts flag in eeprom */ + if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) { + u8 flags = i2c_readreg(av7110, 0xaa, 2); + if (flags != 0xff && (flags & 0x01)) + av7110->full_ts = true; + } + + if (av7110->full_ts) { + printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n"); + spin_lock_init(&av7110->feedlock1); + av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, + &av7110->pt); + if (!av7110->grabbing) + goto err_i2c_del_3; + + saa7146_write(dev, DD1_STREAM_B, 0x00000000); + saa7146_write(dev, MC2, (MASK_10 | MASK_26)); + + saa7146_write(dev, DD1_INIT, 0x00000600); + saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); + + saa7146_write(dev, BRS_CTRL, 0x60000000); + saa7146_write(dev, MC2, MASK_08 | MASK_24); + + /* dma3 */ + saa7146_write(dev, PCI_BT_V1, 0x001c0000 | (saa7146_read(dev, PCI_BT_V1) & ~0x001f0000)); + saa7146_write(dev, BASE_ODD3, 0); + saa7146_write(dev, BASE_EVEN3, 0); + saa7146_write(dev, PROT_ADDR3, TS_WIDTH * TS_HEIGHT); + saa7146_write(dev, PITCH3, TS_WIDTH); + saa7146_write(dev, BASE_PAGE3, av7110->pt.dma | ME1 | 0x90); + saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH); + saa7146_write(dev, MC2, MASK_04 | MASK_20); + + tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110); + + } else if (budgetpatch) { spin_lock_init(&av7110->feedlock1); av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length, &av7110->pt); @@ -2710,11 +2771,13 @@ static int __devexit av7110_detach(struct saa7146_dev* saa) #if defined(CONFIG_INPUT_EVDEV) || defined(CONFIG_INPUT_EVDEV_MODULE) av7110_ir_exit(av7110); #endif - if (budgetpatch) { - /* Disable RPS1 */ - saa7146_write(saa, MC1, MASK_29); - /* VSYNC LOW (inactive) */ - saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + if (budgetpatch || av7110->full_ts) { + if (budgetpatch) { + /* Disable RPS1 */ + saa7146_write(saa, MC1, MASK_29); + /* VSYNC LOW (inactive) */ + saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + } saa7146_write(saa, MC1, MASK_20); /* DMA3 off */ SAA7146_IER_DISABLE(saa, MASK_10); SAA7146_ISR_CLEAR(saa, MASK_10); @@ -2794,7 +2857,7 @@ static void av7110_irq(struct saa7146_dev* dev, u32 *isr) tasklet_schedule(&av7110->gpio_tasklet); } - if ((*isr & MASK_10) && budgetpatch) + if (*isr & MASK_10) tasklet_schedule(&av7110->vpe_tasklet); } diff --git a/linux/drivers/media/dvb/ttpci/av7110.h b/linux/drivers/media/dvb/ttpci/av7110.h index 61e4a7569..e82519e21 100644 --- a/linux/drivers/media/dvb/ttpci/av7110.h +++ b/linux/drivers/media/dvb/ttpci/av7110.h @@ -194,6 +194,7 @@ struct av7110 { unsigned char *grabbing; struct saa7146_pgtable pt; struct tasklet_struct vpe_tasklet; + bool full_ts; int fe_synced; struct mutex pid_mutex; diff --git a/linux/drivers/media/dvb/ttpci/av7110_av.c b/linux/drivers/media/dvb/ttpci/av7110_av.c index 184647ad1..bdc62acf2 100644 --- a/linux/drivers/media/dvb/ttpci/av7110_av.c +++ b/linux/drivers/media/dvb/ttpci/av7110_av.c @@ -788,6 +788,9 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l dprintk(2, "av7110:%p, \n", av7110); + if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE) + return 0; + switch (feed->pes_type) { case 0: if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY) diff --git a/linux/drivers/media/dvb/ttpci/budget-av.c b/linux/drivers/media/dvb/ttpci/budget-av.c index b7d1f2f18..839c94101 100644 --- a/linux/drivers/media/dvb/ttpci/budget-av.c +++ b/linux/drivers/media/dvb/ttpci/budget-av.c @@ -1049,7 +1049,7 @@ static void frontend_init(struct budget_av *budget_av) if (fe == NULL) { printk(KERN_ERR "budget-av: A frontend driver was not found " - "for device %04x/%04x subsystem %04x/%04x\n", + "for device [%04x:%04x] subsystem [%04x:%04x]\n", saa->pci->vendor, saa->pci->device, saa->pci->subsystem_vendor, diff --git a/linux/drivers/media/dvb/ttpci/budget-ci.c b/linux/drivers/media/dvb/ttpci/budget-ci.c index f7388e5fc..0ccc9db6e 100644 --- a/linux/drivers/media/dvb/ttpci/budget-ci.c +++ b/linux/drivers/media/dvb/ttpci/budget-ci.c @@ -34,6 +34,10 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/input.h> +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 23) +/* Fix compile warning */ +#undef BIT +#endif #include <linux/spinlock.h> #include <media/ir-common.h> @@ -1157,7 +1161,7 @@ static void frontend_init(struct budget_ci *budget_ci) } if (budget_ci->budget.dvb_frontend == NULL) { - printk("budget-ci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + printk("budget-ci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", budget_ci->budget.dev->pci->vendor, budget_ci->budget.dev->pci->device, budget_ci->budget.dev->pci->subsystem_vendor, diff --git a/linux/drivers/media/dvb/ttpci/budget-patch.c b/linux/drivers/media/dvb/ttpci/budget-patch.c index 5139b481e..b53b4b6d9 100644 --- a/linux/drivers/media/dvb/ttpci/budget-patch.c +++ b/linux/drivers/media/dvb/ttpci/budget-patch.c @@ -116,7 +116,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long DiseqcSendByte(budget, 0xff); else { saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - udelay(12500); + mdelay(12); + udelay(500); saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); } msleep(20); @@ -359,7 +360,7 @@ static void frontend_init(struct budget_patch* budget) } if (budget->dvb_frontend == NULL) { - printk("dvb-ttpci: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", budget->dev->pci->vendor, budget->dev->pci->device, budget->dev->pci->subsystem_vendor, diff --git a/linux/drivers/media/dvb/ttpci/budget.c b/linux/drivers/media/dvb/ttpci/budget.c index 2293d80c6..d95203d55 100644 --- a/linux/drivers/media/dvb/ttpci/budget.c +++ b/linux/drivers/media/dvb/ttpci/budget.c @@ -46,6 +46,7 @@ #include "lnbp21.h" #include "bsru6.h" #include "bsbe1.h" +#include "tdhd1.h" static int diseqc_method; module_param(diseqc_method, int, 0444); @@ -108,7 +109,8 @@ static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long DiseqcSendByte(budget, 0xff); else { saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); - udelay(12500); + mdelay(12); + udelay(500); saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); } msleep(20); @@ -389,6 +391,13 @@ static struct stv0299_config alps_bsbe1_config_activy = { .set_symbol_rate = alps_bsbe1_set_symbol_rate, }; +static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name) +{ + struct budget *budget = (struct budget *)fe->dvb->priv; + + return request_firmware(fw, name, &budget->dev->pci->dev); +} + static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg) { @@ -510,6 +519,14 @@ static void frontend_init(struct budget *budget) } break; + case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */ + budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap); + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + } + break; + case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */ budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap); if (budget->dvb_frontend) { @@ -549,7 +566,7 @@ static void frontend_init(struct budget *budget) } if (budget->dvb_frontend == NULL) { - printk("budget: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + printk("budget: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", budget->dev->pci->vendor, budget->dev->pci->device, budget->dev->pci->subsystem_vendor, @@ -623,6 +640,7 @@ MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT); MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY); MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY); MAKE_BUDGET_INFO(fsact, "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY); +MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY); static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1003), @@ -633,6 +651,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018), MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60), MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61), + MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60), MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61), { .vendor = 0, diff --git a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index ceae085cb..13085a8e2 100644 --- a/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/linux/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -1634,7 +1634,7 @@ static void frontend_init(struct ttusb* ttusb) } if (ttusb->fe == NULL) { - printk("dvb-ttusb-budget: A frontend driver was not found for device %04x/%04x\n", + printk("dvb-ttusb-budget: A frontend driver was not found for device [%04x:%04x]\n", le16_to_cpu(ttusb->dev->descriptor.idVendor), le16_to_cpu(ttusb->dev->descriptor.idProduct)); } else { diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 4c233c41f..5c2885e17 100644 --- a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1674,7 +1674,7 @@ static int ttusb_dec_probe(struct usb_interface *intf, } if (dec->fe == NULL) { - printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n", + printk("dvb-ttusb-dec: A frontend driver was not found for device [%04x:%04x]\n", le16_to_cpu(dec->udev->descriptor.idVendor), le16_to_cpu(dec->udev->descriptor.idProduct)); } else { diff --git a/linux/drivers/media/radio/dsbr100.c b/linux/drivers/media/radio/dsbr100.c index 93a871985..c03274e46 100644 --- a/linux/drivers/media/radio/dsbr100.c +++ b/linux/drivers/media/radio/dsbr100.c @@ -275,7 +275,7 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct dsbr100_device *radio = video_get_drvdata(video_devdata(file)); + struct dsbr100_device *radio = video_drvdata(file); if (v->index > 0) return -EINVAL; @@ -307,7 +307,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct dsbr100_device *radio = video_get_drvdata(video_devdata(file)); + struct dsbr100_device *radio = video_drvdata(file); radio->curfreq = f->frequency; if (dsbr100_setfreq(radio, radio->curfreq)==-1) @@ -318,7 +318,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct dsbr100_device *radio = video_get_drvdata(video_devdata(file)); + struct dsbr100_device *radio = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = radio->curfreq; @@ -343,7 +343,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct dsbr100_device *radio = video_get_drvdata(video_devdata(file)); + struct dsbr100_device *radio = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -356,7 +356,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct dsbr100_device *radio = video_get_drvdata(video_devdata(file)); + struct dsbr100_device *radio = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -406,7 +406,7 @@ static int vidioc_s_audio(struct file *file, void *priv, static int usb_dsbr100_open(struct inode *inode, struct file *file) { - struct dsbr100_device *radio=video_get_drvdata(video_devdata(file)); + struct dsbr100_device *radio = video_drvdata(file); lock_kernel(); radio->users = 1; @@ -425,7 +425,7 @@ static int usb_dsbr100_open(struct inode *inode, struct file *file) static int usb_dsbr100_close(struct inode *inode, struct file *file) { - struct dsbr100_device *radio=video_get_drvdata(video_devdata(file)); + struct dsbr100_device *radio = video_drvdata(file); if (!radio) return -ENODEV; @@ -497,7 +497,7 @@ static int usb_dsbr100_probe(struct usb_interface *intf, radio->usbdev = interface_to_usbdev(intf); radio->curfreq = FREQ_MIN*FREQ_MUL; video_set_drvdata(radio->videodev, radio); - if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) { + if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr) < 0) { warn("Could not register video device"); video_device_release(radio->videodev); kfree(radio->transfer_buffer); diff --git a/linux/drivers/media/radio/radio-aimslab.c b/linux/drivers/media/radio/radio-aimslab.c index 516677a98..483ada689 100644 --- a/linux/drivers/media/radio/radio-aimslab.c +++ b/linux/drivers/media/radio/radio-aimslab.c @@ -52,6 +52,7 @@ static struct mutex lock; struct rt_device { + unsigned long in_use; int port; int curvol; unsigned long curfreq; @@ -246,8 +247,7 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt = video_drvdata(file); if (v->index > 0) return -EINVAL; @@ -274,8 +274,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt = video_drvdata(file); rt->curfreq = f->frequency; rt_setfreq(rt, rt->curfreq); @@ -285,8 +284,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = rt->curfreq; @@ -311,8 +309,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -328,8 +325,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -379,10 +375,21 @@ static int vidioc_s_audio(struct file *file, void *priv, static struct rt_device rtrack_unit; +static int rtrack_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &rtrack_unit.in_use) ? -EBUSY : 0; +} + +static int rtrack_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &rtrack_unit.in_use); + return 0; +} + static const struct file_operations rtrack_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = rtrack_exclusive_open, + .release = rtrack_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -409,6 +416,7 @@ static struct video_device rtrack_radio = { .name = "RadioTrack radio", .fops = &rtrack_fops, .ioctl_ops = &rtrack_ioctl_ops, + .release = video_device_release_empty, }; static int __init rtrack_init(void) @@ -425,10 +433,9 @@ static int __init rtrack_init(void) return -EBUSY; } - rtrack_radio.priv=&rtrack_unit; + video_set_drvdata(&rtrack_radio, &rtrack_unit); - if(video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 2); return -EINVAL; } diff --git a/linux/drivers/media/radio/radio-aztech.c b/linux/drivers/media/radio/radio-aztech.c index 8adb1b003..9ce1908ac 100644 --- a/linux/drivers/media/radio/radio-aztech.c +++ b/linux/drivers/media/radio/radio-aztech.c @@ -71,6 +71,7 @@ static struct mutex lock; struct az_device { + unsigned long in_use; int curvol; unsigned long curfreq; int stereo; @@ -196,8 +197,7 @@ static int vidioc_querycap (struct file *file, void *priv, static int vidioc_g_tuner (struct file *file, void *priv, struct v4l2_tuner *v) { - struct video_device *dev = video_devdata(file); - struct az_device *az = dev->priv; + struct az_device *az = video_drvdata(file); if (v->index > 0) return -EINVAL; @@ -265,8 +265,7 @@ static int vidioc_s_audio (struct file *file, void *priv, static int vidioc_s_frequency (struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct az_device *az = dev->priv; + struct az_device *az = video_drvdata(file); az->curfreq = f->frequency; az_setfreq(az, az->curfreq); @@ -276,8 +275,7 @@ static int vidioc_s_frequency (struct file *file, void *priv, static int vidioc_g_frequency (struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct az_device *az = dev->priv; + struct az_device *az = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = az->curfreq; @@ -303,8 +301,7 @@ static int vidioc_queryctrl (struct file *file, void *priv, static int vidioc_g_ctrl (struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct az_device *az = dev->priv; + struct az_device *az = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -323,8 +320,7 @@ static int vidioc_g_ctrl (struct file *file, void *priv, static int vidioc_s_ctrl (struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct az_device *az = dev->priv; + struct az_device *az = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -343,10 +339,21 @@ static int vidioc_s_ctrl (struct file *file, void *priv, static struct az_device aztech_unit; +static int aztech_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &aztech_unit.in_use) ? -EBUSY : 0; +} + +static int aztech_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &aztech_unit.in_use); + return 0; +} + static const struct file_operations aztech_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = aztech_exclusive_open, + .release = aztech_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -370,9 +377,10 @@ static const struct v4l2_ioctl_ops aztech_ioctl_ops = { }; static struct video_device aztech_radio = { - .name = "Aztech radio", - .fops = &aztech_fops, - .ioctl_ops = &aztech_ioctl_ops, + .name = "Aztech radio", + .fops = &aztech_fops, + .ioctl_ops = &aztech_ioctl_ops, + .release = video_device_release_empty, }; module_param_named(debug,aztech_radio.debug, int, 0644); @@ -393,10 +401,9 @@ static int __init aztech_init(void) } mutex_init(&lock); - aztech_radio.priv=&aztech_unit; + video_set_drvdata(&aztech_radio, &aztech_unit); - if(video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io,2); return -EINVAL; } diff --git a/linux/drivers/media/radio/radio-cadet.c b/linux/drivers/media/radio/radio-cadet.c index 6588f0cd3..f40c079ea 100644 --- a/linux/drivers/media/radio/radio-cadet.c +++ b/linux/drivers/media/radio/radio-cadet.c @@ -619,6 +619,7 @@ static struct video_device cadet_radio = { .name = "Cadet radio", .fops = &cadet_fops, .ioctl_ops = &cadet_ioctl_ops, + .release = video_device_release_empty, }; #ifdef CONFIG_PNP @@ -712,7 +713,7 @@ static int __init cadet_init(void) } if (!request_region(io,2,"cadet")) goto fail; - if(video_register_device(&cadet_radio,VFL_TYPE_RADIO,radio_nr)==-1) { + if (video_register_device(&cadet_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io,2); goto fail; } diff --git a/linux/drivers/media/radio/radio-gemtek-pci.c b/linux/drivers/media/radio/radio-gemtek-pci.c index efee362c7..06a91be87 100644 --- a/linux/drivers/media/radio/radio-gemtek-pci.c +++ b/linux/drivers/media/radio/radio-gemtek-pci.c @@ -101,9 +101,8 @@ struct gemtek_pci_card { u8 mute; }; -static const char rcsid[] = "$Id: radio-gemtek-pci.c,v 1.1 2001/07/23 08:08:16 ted Exp ted $"; - static int nr_radio = -1; +static unsigned long in_use; static inline u8 gemtek_pci_out( u16 value, u32 port ) { @@ -206,8 +205,7 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct video_device *dev = video_devdata(file); - struct gemtek_pci_card *card = dev->priv; + struct gemtek_pci_card *card = video_drvdata(file); if (v->index > 0) return -EINVAL; @@ -234,8 +232,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct gemtek_pci_card *card = dev->priv; + struct gemtek_pci_card *card = video_drvdata(file); if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) || (f->frequency > GEMTEK_PCI_RANGE_HIGH) ) @@ -249,8 +246,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct gemtek_pci_card *card = dev->priv; + struct gemtek_pci_card *card = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = card->current_frequency; @@ -274,8 +270,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct gemtek_pci_card *card = dev->priv; + struct gemtek_pci_card *card = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -294,8 +289,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct gemtek_pci_card *card = dev->priv; + struct gemtek_pci_card *card = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -365,10 +359,21 @@ MODULE_DEVICE_TABLE( pci, gemtek_pci_id ); static int mx = 1; +static int gemtek_pci_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &in_use) ? -EBUSY : 0; +} + +static int gemtek_pci_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &in_use); + return 0; +} + static const struct file_operations gemtek_pci_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = gemtek_pci_exclusive_open, + .release = gemtek_pci_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -392,9 +397,10 @@ static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = { }; static struct video_device vdev_template = { - .name = "Gemtek PCI Radio", - .fops = &gemtek_pci_fops, - .ioctl_ops = &gemtek_pci_ioctl_ops, + .name = "Gemtek PCI Radio", + .fops = &gemtek_pci_fops, + .ioctl_ops = &gemtek_pci_ioctl_ops, + .release = video_device_release_empty, }; static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id ) @@ -426,13 +432,13 @@ static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci } *devradio = vdev_template; - if ( video_register_device( devradio, VFL_TYPE_RADIO , nr_radio) == -1 ) { + if (video_register_device(devradio, VFL_TYPE_RADIO, nr_radio) < 0) { kfree( devradio ); goto err_video; } card->videodev = devradio; - devradio->priv = card; + video_set_drvdata(devradio, card); gemtek_pci_mute( card ); #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22) diff --git a/linux/drivers/media/radio/radio-gemtek.c b/linux/drivers/media/radio/radio-gemtek.c index bf1837ab2..003c7b2f7 100644 --- a/linux/drivers/media/radio/radio-gemtek.c +++ b/linux/drivers/media/radio/radio-gemtek.c @@ -58,6 +58,7 @@ static int shutdown = 1; static int keepmuted = 1; static int initmute = 1; static int radio_nr = -1; +static unsigned long in_use; module_param(io, int, 0444); MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic " @@ -394,10 +395,21 @@ static struct v4l2_queryctrl radio_qctrl[] = { } }; +static int gemtek_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &in_use) ? -EBUSY : 0; +} + +static int gemtek_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &in_use); + return 0; +} + static const struct file_operations gemtek_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = gemtek_exclusive_open, + .release = gemtek_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -448,8 +460,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; + struct gemtek_device *rt = video_drvdata(file); gemtek_setfreq(rt, f->frequency); @@ -459,8 +470,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; + struct gemtek_device *rt = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = rt->lastfreq; @@ -484,8 +494,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; + struct gemtek_device *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -504,8 +513,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct gemtek_device *rt = dev->priv; + struct gemtek_device *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -570,9 +578,10 @@ static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { }; static struct video_device gemtek_radio = { - .name = "GemTek Radio card", - .fops = &gemtek_fops, - .ioctl_ops = &gemtek_ioctl_ops, + .name = "GemTek Radio card", + .fops = &gemtek_fops, + .ioctl_ops = &gemtek_ioctl_ops, + .release = video_device_release_empty, }; /* @@ -611,10 +620,9 @@ static int __init gemtek_init(void) return -EINVAL; } - gemtek_radio.priv = &gemtek_unit; + video_set_drvdata(&gemtek_radio, &gemtek_unit); - if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, - radio_nr) == -1) { + if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 1); return -EBUSY; } diff --git a/linux/drivers/media/radio/radio-maestro.c b/linux/drivers/media/radio/radio-maestro.c index 3b382e2b3..326405d3b 100644 --- a/linux/drivers/media/radio/radio-maestro.c +++ b/linux/drivers/media/radio/radio-maestro.c @@ -76,7 +76,21 @@ static struct v4l2_queryctrl radio_qctrl[] = { static int radio_nr = -1; module_param(radio_nr, int, 0); +static unsigned long in_use; + static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent); + +static int maestro_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &in_use) ? -EBUSY : 0; +} + +static int maestro_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &in_use); + return 0; +} + static void maestro_remove(struct pci_dev *pdev); static struct pci_device_id maestro_r_pci_tbl[] = { @@ -99,8 +113,8 @@ static struct pci_driver maestro_r_driver = { static const struct file_operations maestro_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = maestro_exclusive_open, + .release = maestro_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -197,8 +211,7 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct video_device *dev = video_devdata(file); - struct radio_device *card = video_get_drvdata(dev); + struct radio_device *card = video_drvdata(file); if (v->index > 0) return -EINVAL; @@ -230,8 +243,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct radio_device *card = video_get_drvdata(dev); + struct radio_device *card = video_drvdata(file); if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) return -EINVAL; @@ -242,8 +254,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct radio_device *card = video_get_drvdata(dev); + struct radio_device *card = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = BITS2FREQ(radio_bits_get(card)); @@ -268,8 +279,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct radio_device *card = video_get_drvdata(dev); + struct radio_device *card = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -282,8 +292,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct radio_device *card = video_get_drvdata(dev); + struct radio_device *card = video_drvdata(file); register u16 io = card->io; register u16 omask = inw(io + IO_MASK); @@ -375,6 +384,7 @@ static struct video_device maestro_radio = { .name = "Maestro radio", .fops = &maestro_fops, .ioctl_ops = &maestro_ioctl_ops, + .release = video_device_release, }; static int __devinit maestro_probe(struct pci_dev *pdev, @@ -410,8 +420,7 @@ static int __devinit maestro_probe(struct pci_dev *pdev, video_set_drvdata(maestro_radio_inst, radio_unit); pci_set_drvdata(pdev, maestro_radio_inst); - retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO, - radio_nr); + retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO, radio_nr); if (retval) { printk(KERN_ERR "can't register video device!\n"); goto errfr1; diff --git a/linux/drivers/media/radio/radio-maxiradio.c b/linux/drivers/media/radio/radio-maxiradio.c index 0f6bbd81b..4aea352cb 100644 --- a/linux/drivers/media/radio/radio-maxiradio.c +++ b/linux/drivers/media/radio/radio-maxiradio.c @@ -86,6 +86,7 @@ static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ; static int radio_nr = -1; module_param(radio_nr, int, 0); +static unsigned long in_use; #define FREQ_LO 50*16000 #define FREQ_HI 150*16000 @@ -100,10 +101,21 @@ module_param(radio_nr, int, 0); #define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) +static int maxiradio_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &in_use) ? -EBUSY : 0; +} + +static int maxiradio_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &in_use); + return 0; +} + static const struct file_operations maxiradio_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = maxiradio_exclusive_open, + .release = maxiradio_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -157,28 +169,28 @@ static void set_freq(__u16 io, __u32 freq) { unsigned long int si; int bl; - int data = FREQ2BITS(freq); + int val = FREQ2BITS(freq); /* TEA5757 shift register bits (see pdf) */ - outbit(0,io); // 24 search - outbit(1,io); // 23 search up/down + outbit(0, io); /* 24 search */ + outbit(1, io); /* 23 search up/down */ - outbit(0,io); // 22 stereo/mono + outbit(0, io); /* 22 stereo/mono */ - outbit(0,io); // 21 band - outbit(0,io); // 20 band (only 00=FM works I think) + outbit(0, io); /* 21 band */ + outbit(0, io); /* 20 band (only 00=FM works I think) */ - outbit(0,io); // 19 port ? - outbit(0,io); // 18 port ? + outbit(0, io); /* 19 port ? */ + outbit(0, io); /* 18 port ? */ - outbit(0,io); // 17 search level - outbit(0,io); // 16 search level + outbit(0, io); /* 17 search level */ + outbit(0, io); /* 16 search level */ si = 0x8000; - for (bl = 1; bl <= 16 ; bl++) { - outbit(data & si,io); - si >>=1; + for (bl = 1; bl <= 16; bl++) { + outbit(val & si, io); + si >>= 1; } dprintk(1, "Radio freq set to %d.%02d MHz\n", @@ -220,8 +232,7 @@ static int vidioc_querycap (struct file *file, void *priv, static int vidioc_g_tuner (struct file *file, void *priv, struct v4l2_tuner *v) { - struct video_device *dev = video_devdata(file); - struct radio_device *card=dev->priv; + struct radio_device *card = video_drvdata(file); if (v->index > 0) return -EINVAL; @@ -291,8 +302,7 @@ static int vidioc_s_audio (struct file *file, void *priv, static int vidioc_s_frequency (struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct radio_device *card=dev->priv; + struct radio_device *card = video_drvdata(file); if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", @@ -313,8 +323,7 @@ static int vidioc_s_frequency (struct file *file, void *priv, static int vidioc_g_frequency (struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct radio_device *card=dev->priv; + struct radio_device *card = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = card->freq; @@ -344,8 +353,7 @@ static int vidioc_queryctrl (struct file *file, void *priv, static int vidioc_g_ctrl (struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct radio_device *card=dev->priv; + struct radio_device *card = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -359,8 +367,7 @@ static int vidioc_g_ctrl (struct file *file, void *priv, static int vidioc_s_ctrl (struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct radio_device *card=dev->priv; + struct radio_device *card = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -391,9 +398,10 @@ static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { }; static struct video_device maxiradio_radio = { - .name = "Maxi Radio FM2000 radio", - .fops = &maxiradio_fops, - .ioctl_ops = &maxiradio_ioctl_ops, + .name = "Maxi Radio FM2000 radio", + .fops = &maxiradio_fops, + .ioctl_ops = &maxiradio_ioctl_ops, + .release = video_device_release_empty, }; static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -409,9 +417,9 @@ static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_d radio_unit.io = pci_resource_start(pdev, 0); mutex_init(&radio_unit.lock); - maxiradio_radio.priv = &radio_unit; + video_set_drvdata(&maxiradio_radio, &radio_unit); - if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr)==-1) { + if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr) < 0) { printk("radio-maxiradio: can't register device!"); goto err_out_free_region; } diff --git a/linux/drivers/media/radio/radio-rtrack2.c b/linux/drivers/media/radio/radio-rtrack2.c index 31d6eabbb..59592bb84 100644 --- a/linux/drivers/media/radio/radio-rtrack2.c +++ b/linux/drivers/media/radio/radio-rtrack2.c @@ -53,6 +53,7 @@ static spinlock_t lock; struct rt_device { + unsigned long in_use; int port; unsigned long curfreq; int muted; @@ -154,8 +155,7 @@ static int rt_getsigstr(struct rt_device *dev) static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt = video_drvdata(file); if (v->index > 0) return -EINVAL; @@ -174,8 +174,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt = video_drvdata(file); rt->curfreq = f->frequency; rt_setfreq(rt, rt->curfreq); @@ -185,8 +184,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = rt->curfreq; @@ -211,8 +209,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -231,8 +228,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct rt_device *rt = dev->priv; + struct rt_device *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -285,10 +281,21 @@ static int vidioc_s_audio(struct file *file, void *priv, static struct rt_device rtrack2_unit; +static int rtrack2_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &rtrack2_unit.in_use) ? -EBUSY : 0; +} + +static int rtrack2_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &rtrack2_unit.in_use); + return 0; +} + static const struct file_operations rtrack2_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = rtrack2_exclusive_open, + .release = rtrack2_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -315,6 +322,7 @@ static struct video_device rtrack2_radio = { .name = "RadioTrack II radio", .fops = &rtrack2_fops, .ioctl_ops = &rtrack2_ioctl_ops, + .release = video_device_release_empty, }; static int __init rtrack2_init(void) @@ -330,11 +338,10 @@ static int __init rtrack2_init(void) return -EBUSY; } - rtrack2_radio.priv=&rtrack2_unit; + video_set_drvdata(&rtrack2_radio, &rtrack2_unit); spin_lock_init(&lock); - if(video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 4); return -EINVAL; } diff --git a/linux/drivers/media/radio/radio-sf16fmi.c b/linux/drivers/media/radio/radio-sf16fmi.c index d4433b6a3..edf7480bc 100644 --- a/linux/drivers/media/radio/radio-sf16fmi.c +++ b/linux/drivers/media/radio/radio-sf16fmi.c @@ -46,6 +46,7 @@ static struct v4l2_queryctrl radio_qctrl[] = { struct fmi_device { + unsigned long in_use; int port; int curvol; /* 1 or 0 */ unsigned long curfreq; /* freq in kHz */ @@ -147,8 +148,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { int mult; - struct video_device *dev = video_devdata(file); - struct fmi_device *fmi = dev->priv; + struct fmi_device *fmi = video_drvdata(file); if (v->index > 0) return -EINVAL; @@ -176,8 +176,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct fmi_device *fmi = dev->priv; + struct fmi_device *fmi = video_drvdata(file); if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) f->frequency *= 1000; @@ -194,8 +193,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct fmi_device *fmi = dev->priv; + struct fmi_device *fmi = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = fmi->curfreq; @@ -222,8 +220,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct fmi_device *fmi = dev->priv; + struct fmi_device *fmi = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -236,8 +233,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct fmi_device *fmi = dev->priv; + struct fmi_device *fmi = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -285,10 +281,21 @@ static int vidioc_s_audio(struct file *file, void *priv, static struct fmi_device fmi_unit; +static int fmi_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &fmi_unit.in_use) ? -EBUSY : 0; +} + +static int fmi_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &fmi_unit.in_use); + return 0; +} + static const struct file_operations fmi_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = fmi_exclusive_open, + .release = fmi_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -315,6 +322,7 @@ static struct video_device fmi_radio = { .name = "SF16FMx radio", .fops = &fmi_fops, .ioctl_ops = &fmi_ioctl_ops, + .release = video_device_release_empty, }; /* ladis: this is my card. does any other types exist? */ @@ -374,11 +382,11 @@ static int __init fmi_init(void) fmi_unit.curvol = 0; fmi_unit.curfreq = 0; fmi_unit.flags = V4L2_TUNER_CAP_LOW; - fmi_radio.priv = &fmi_unit; + video_set_drvdata(&fmi_radio, &fmi_unit); mutex_init(&lock); - if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) == -1) { + if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 2); return -EINVAL; } diff --git a/linux/drivers/media/radio/radio-sf16fmr2.c b/linux/drivers/media/radio/radio-sf16fmr2.c index 7b7748561..f5aebc9da 100644 --- a/linux/drivers/media/radio/radio-sf16fmr2.c +++ b/linux/drivers/media/radio/radio-sf16fmr2.c @@ -65,6 +65,7 @@ static struct v4l2_queryctrl radio_qctrl[] = { /* this should be static vars for module size */ struct fmr2_device { + unsigned long in_use; int port; int curvol; /* 0-15 */ int mute; @@ -230,8 +231,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { int mult; - struct video_device *dev = video_devdata(file); - struct fmr2_device *fmr2 = dev->priv; + struct fmr2_device *fmr2 = video_drvdata(file); if (v->index > 0) return -EINVAL; @@ -263,8 +263,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct fmr2_device *fmr2 = dev->priv; + struct fmr2_device *fmr2 = video_drvdata(file); if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) f->frequency *= 1000; @@ -287,8 +286,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct fmr2_device *fmr2 = dev->priv; + struct fmr2_device *fmr2 = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = fmr2->curfreq; @@ -314,8 +312,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct fmr2_device *fmr2 = dev->priv; + struct fmr2_device *fmr2 = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -331,8 +328,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct fmr2_device *fmr2 = dev->priv; + struct fmr2_device *fmr2 = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -401,10 +397,21 @@ static int vidioc_s_audio(struct file *file, void *priv, static struct fmr2_device fmr2_unit; +static int fmr2_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &fmr2_unit.in_use) ? -EBUSY : 0; +} + +static int fmr2_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &fmr2_unit.in_use); + return 0; +} + static const struct file_operations fmr2_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = fmr2_exclusive_open, + .release = fmr2_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -431,6 +438,7 @@ static struct video_device fmr2_radio = { .name = "SF16FMR2 radio", .fops = &fmr2_fops, .ioctl_ops = &fmr2_ioctl_ops, + .release = video_device_release_empty, }; static int __init fmr2_init(void) @@ -442,7 +450,7 @@ static int __init fmr2_init(void) fmr2_unit.stereo = 1; fmr2_unit.flags = V4L2_TUNER_CAP_LOW; fmr2_unit.card_type = 0; - fmr2_radio.priv = &fmr2_unit; + video_set_drvdata(&fmr2_radio, &fmr2_unit); mutex_init(&lock); diff --git a/linux/drivers/media/radio/radio-si470x.c b/linux/drivers/media/radio/radio-si470x.c index 3b1f630a9..871a63a87 100644 --- a/linux/drivers/media/radio/radio-si470x.c +++ b/linux/drivers/media/radio/radio-si470x.c @@ -991,7 +991,7 @@ static void si470x_work(struct work_struct *work) static ssize_t si470x_fops_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct si470x_device *radio = video_drvdata(file); int retval = 0; unsigned int block_count = 0; @@ -1052,7 +1052,7 @@ done: static unsigned int si470x_fops_poll(struct file *file, struct poll_table_struct *pts) { - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct si470x_device *radio = video_drvdata(file); int retval = 0; /* switch on rds reception */ @@ -1076,7 +1076,7 @@ static unsigned int si470x_fops_poll(struct file *file, */ static int si470x_fops_open(struct inode *inode, struct file *file) { - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct si470x_device *radio = video_drvdata(file); int retval; lock_kernel(); @@ -1106,7 +1106,7 @@ done: */ static int si470x_fops_release(struct inode *inode, struct file *file) { - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct si470x_device *radio = video_drvdata(file); int retval = 0; /* safety check */ @@ -1289,7 +1289,7 @@ done: static int si470x_vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct si470x_device *radio = video_drvdata(file); int retval = 0; /* safety checks */ @@ -1325,7 +1325,7 @@ done: static int si470x_vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct si470x_device *radio = video_drvdata(file); int retval = 0; /* safety checks */ @@ -1412,7 +1412,7 @@ done: static int si470x_vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct si470x_device *radio = video_drvdata(file); int retval = 0; /* safety checks */ @@ -1478,7 +1478,7 @@ done: static int si470x_vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *tuner) { - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct si470x_device *radio = video_drvdata(file); int retval = 0; /* safety checks */ @@ -1512,7 +1512,7 @@ done: static int si470x_vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *freq) { - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct si470x_device *radio = video_drvdata(file); int retval = 0; /* safety checks */ @@ -1541,7 +1541,7 @@ done: static int si470x_vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *freq) { - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct si470x_device *radio = video_drvdata(file); int retval = 0; /* safety checks */ @@ -1570,7 +1570,7 @@ done: static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, struct v4l2_hw_freq_seek *seek) { - struct si470x_device *radio = video_get_drvdata(video_devdata(file)); + struct si470x_device *radio = video_drvdata(file); int retval = 0; /* safety checks */ @@ -1701,8 +1701,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, INIT_DELAYED_WORK(&radio->work, si470x_work); /* register video device */ - if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { - retval = -EIO; + retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); + if (retval) { printk(KERN_WARNING DRIVER_NAME ": Could not register video device\n"); goto err_all; diff --git a/linux/drivers/media/radio/radio-terratec.c b/linux/drivers/media/radio/radio-terratec.c index 768582f53..3066b08f0 100644 --- a/linux/drivers/media/radio/radio-terratec.c +++ b/linux/drivers/media/radio/radio-terratec.c @@ -80,6 +80,7 @@ static spinlock_t lock; struct tt_device { + unsigned long in_use; int port; int curvol; unsigned long curfreq; @@ -221,8 +222,7 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct video_device *dev = video_devdata(file); - struct tt_device *tt = dev->priv; + struct tt_device *tt = video_drvdata(file); if (v->index > 0) return -EINVAL; @@ -249,8 +249,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct tt_device *tt = dev->priv; + struct tt_device *tt = video_drvdata(file); tt->curfreq = f->frequency; tt_setfreq(tt, tt->curfreq); @@ -260,8 +259,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct tt_device *tt = dev->priv; + struct tt_device *tt = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = tt->curfreq; @@ -286,8 +284,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct tt_device *tt = dev->priv; + struct tt_device *tt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -306,8 +303,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct tt_device *tt = dev->priv; + struct tt_device *tt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -357,10 +353,21 @@ static int vidioc_s_audio(struct file *file, void *priv, static struct tt_device terratec_unit; +static int terratec_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &terratec_unit.in_use) ? -EBUSY : 0; +} + +static int terratec_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &terratec_unit.in_use); + return 0; +} + static const struct file_operations terratec_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = terratec_exclusive_open, + .release = terratec_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -387,6 +394,7 @@ static struct video_device terratec_radio = { .name = "TerraTec ActiveRadio", .fops = &terratec_fops, .ioctl_ops = &terratec_ioctl_ops, + .release = video_device_release_empty, }; static int __init terratec_init(void) @@ -402,12 +410,11 @@ static int __init terratec_init(void) return -EBUSY; } - terratec_radio.priv=&terratec_unit; + video_set_drvdata(&terratec_radio, &terratec_unit); spin_lock_init(&lock); - if(video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io,2); return -EINVAL; } diff --git a/linux/drivers/media/radio/radio-trust.c b/linux/drivers/media/radio/radio-trust.c index 648007027..a334ce27e 100644 --- a/linux/drivers/media/radio/radio-trust.c +++ b/linux/drivers/media/radio/radio-trust.c @@ -79,6 +79,7 @@ static __u16 curtreble; static unsigned long curfreq; static int curstereo; static int curmute; +static unsigned long in_use; /* i2c addresses */ #define TDA7318_ADDR 0x88 @@ -340,10 +341,21 @@ static int vidioc_s_audio(struct file *file, void *priv, return 0; } +static int trust_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &in_use) ? -EBUSY : 0; +} + +static int trust_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &in_use); + return 0; +} + static const struct file_operations trust_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = trust_exclusive_open, + .release = trust_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -370,6 +382,7 @@ static struct video_device trust_radio = { .name = "Trust FM Radio", .fops = &trust_fops, .ioctl_ops = &trust_ioctl_ops, + .release = video_device_release_empty, }; static int __init trust_init(void) @@ -382,8 +395,7 @@ static int __init trust_init(void) printk(KERN_ERR "trust: port 0x%x already in use\n", io); return -EBUSY; } - if(video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr)==-1) - { + if (video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 2); return -EINVAL; } diff --git a/linux/drivers/media/radio/radio-typhoon.c b/linux/drivers/media/radio/radio-typhoon.c index fa66168d7..c7ea37389 100644 --- a/linux/drivers/media/radio/radio-typhoon.c +++ b/linux/drivers/media/radio/radio-typhoon.c @@ -80,7 +80,7 @@ static struct v4l2_queryctrl radio_qctrl[] = { #endif struct typhoon_device { - int users; + unsigned long in_use; int iobase; int curvol; int muted; @@ -224,8 +224,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct typhoon_device *typhoon = dev->priv; + struct typhoon_device *typhoon = video_drvdata(file); typhoon->curfreq = f->frequency; typhoon_setfreq(typhoon, typhoon->curfreq); @@ -235,8 +234,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct typhoon_device *typhoon = dev->priv; + struct typhoon_device *typhoon = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = typhoon->curfreq; @@ -262,8 +260,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct typhoon_device *typhoon = dev->priv; + struct typhoon_device *typhoon = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -279,8 +276,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl (struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct typhoon_device *typhoon = dev->priv; + struct typhoon_device *typhoon = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -335,10 +331,21 @@ static struct typhoon_device typhoon_unit = .mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ, }; +static int typhoon_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &typhoon_unit.in_use) ? -EBUSY : 0; +} + +static int typhoon_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &typhoon_unit.in_use); + return 0; +} + static const struct file_operations typhoon_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = typhoon_exclusive_open, + .release = typhoon_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -365,6 +372,7 @@ static struct video_device typhoon_radio = { .name = "Typhoon Radio", .fops = &typhoon_fops, .ioctl_ops = &typhoon_ioctl_ops, + .release = video_device_release_empty, }; #ifdef CONFIG_RADIO_TYPHOON_PROC_FS @@ -447,9 +455,8 @@ static int __init typhoon_init(void) return -EBUSY; } - typhoon_radio.priv = &typhoon_unit; - if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) == -1) - { + video_set_drvdata(&typhoon_radio, &typhoon_unit); + if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 8); return -EINVAL; } diff --git a/linux/drivers/media/radio/radio-zoltrix.c b/linux/drivers/media/radio/radio-zoltrix.c index ef6d6a66f..615165b57 100644 --- a/linux/drivers/media/radio/radio-zoltrix.c +++ b/linux/drivers/media/radio/radio-zoltrix.c @@ -70,6 +70,7 @@ static int io = CONFIG_RADIO_ZOLTRIX_PORT; static int radio_nr = -1; struct zol_device { + unsigned long in_use; int port; int curvol; unsigned long curfreq; @@ -246,8 +247,7 @@ static int vidioc_querycap(struct file *file, void *priv, static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct video_device *dev = video_devdata(file); - struct zol_device *zol = dev->priv; + struct zol_device *zol = video_drvdata(file); if (v->index > 0) return -EINVAL; @@ -277,8 +277,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct zol_device *zol = dev->priv; + struct zol_device *zol = video_drvdata(file); zol->curfreq = f->frequency; zol_setfreq(zol, zol->curfreq); @@ -288,8 +287,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct video_device *dev = video_devdata(file); - struct zol_device *zol = dev->priv; + struct zol_device *zol = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = zol->curfreq; @@ -314,8 +312,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct zol_device *zol = dev->priv; + struct zol_device *zol = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -331,8 +328,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct zol_device *zol = dev->priv; + struct zol_device *zol = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -397,11 +393,22 @@ static int vidioc_s_audio(struct file *file, void *priv, static struct zol_device zoltrix_unit; +static int zoltrix_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &zoltrix_unit.in_use) ? -EBUSY : 0; +} + +static int zoltrix_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &zoltrix_unit.in_use); + return 0; +} + static const struct file_operations zoltrix_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = zoltrix_exclusive_open, + .release = zoltrix_exclusive_release, .ioctl = video_ioctl2, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -428,6 +435,7 @@ static struct video_device zoltrix_radio = { .name = "Zoltrix Radio Plus", .fops = &zoltrix_fops, .ioctl_ops = &zoltrix_ioctl_ops, + .release = video_device_release_empty, }; static int __init zoltrix_init(void) @@ -441,14 +449,13 @@ static int __init zoltrix_init(void) return -ENXIO; } - zoltrix_radio.priv = &zoltrix_unit; + video_set_drvdata(&zoltrix_radio, &zoltrix_unit); if (!request_region(io, 2, "zoltrix")) { printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io); return -EBUSY; } - if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) == -1) - { + if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) < 0) { release_region(io, 2); return -EINVAL; } diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig index 7b2925808..7f7482bff 100644 --- a/linux/drivers/media/video/Kconfig +++ b/linux/drivers/media/video/Kconfig @@ -822,7 +822,7 @@ config VIDEO_PXA27x config VIDEO_SH_MOBILE_CEU tristate "SuperH Mobile CEU Interface driver" - depends on VIDEO_DEV && SOC_CAMERA + depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA select VIDEOBUF_DMA_CONTIG ---help--- This is a v4l2 driver for the SuperH Mobile CEU Interface diff --git a/linux/drivers/media/video/arv.c b/linux/drivers/media/video/arv.c index 9e96e7773..a6c2ff1b4 100644 --- a/linux/drivers/media/video/arv.c +++ b/linux/drivers/media/video/arv.c @@ -117,6 +117,7 @@ struct ar_device { int width, height; int frame_bytes, line_bytes; wait_queue_head_t wait; + unsigned long in_use; struct mutex lock; }; @@ -270,7 +271,7 @@ static inline void wait_for_vertical_sync(int exp_line) static ssize_t ar_read(struct file *file, char *buf, size_t count, loff_t *ppos) { struct video_device *v = video_devdata(file); - struct ar_device *ar = v->priv; + struct ar_device *ar = video_get_drvdata(v); long ret = ar->frame_bytes; /* return read bytes */ unsigned long arvcr1 = 0; unsigned long flags; @@ -400,7 +401,7 @@ static int ar_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { struct video_device *dev = video_devdata(file); - struct ar_device *ar = dev->priv; + struct ar_device *ar = video_get_drvdata(dev); DEBUG(1, "ar_ioctl()\n"); switch(cmd) { @@ -630,7 +631,7 @@ static void ar_interrupt(int irq, void *dev) */ static int ar_initialize(struct video_device *dev) { - struct ar_device *ar = dev->priv; + struct ar_device *ar = video_get_drvdata(dev); unsigned long cr = 0; int i,found=0; @@ -737,7 +738,7 @@ static int ar_initialize(struct video_device *dev) void ar_release(struct video_device *vfd) { - struct ar_device *ar = vfd->priv; + struct ar_device *ar = video_get_drvdata(vfd); mutex_lock(&ar->lock); video_device_release(vfd); } @@ -747,10 +748,23 @@ void ar_release(struct video_device *vfd) * Video4Linux Module functions * ****************************************************************************/ +static struct ar_device ardev; + +static int ar_exclusive_open(struct inode *inode, struct file *file) +{ + return test_and_set_bit(0, &ardev.in_use) ? -EBUSY : 0; +} + +static int ar_exclusive_release(struct inode *inode, struct file *file) +{ + clear_bit(0, &ardev.in_use); + return 0; +} + static const struct file_operations ar_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = ar_exclusive_open, + .release = ar_exclusive_release, .read = ar_read, .ioctl = ar_ioctl, #ifdef CONFIG_COMPAT @@ -767,7 +781,6 @@ static struct video_device ar_template = { }; #define ALIGN4(x) ((((int)(x)) & 0x3) == 0) -static struct ar_device ardev; static int __init ar_init(void) { @@ -807,7 +820,7 @@ static int __init ar_init(void) return -ENOMEM; } memcpy(ar->vdev, &ar_template, sizeof(ar_template)); - ar->vdev->priv = ar; + video_set_drvdata(ar->vdev, ar); if (vga) { ar->width = AR_WIDTH_VGA; diff --git a/linux/drivers/media/video/au0828/au0828-cards.c b/linux/drivers/media/video/au0828/au0828-cards.c index 14b9fc9bb..ed48908a9 100644 --- a/linux/drivers/media/video/au0828/au0828-cards.c +++ b/linux/drivers/media/video/au0828/au0828-cards.c @@ -1,7 +1,7 @@ /* * Driver for the Auvitek USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/video/au0828/au0828-cards.h b/linux/drivers/media/video/au0828/au0828-cards.h index 102ed03dc..48a1882c2 100644 --- a/linux/drivers/media/video/au0828/au0828-cards.h +++ b/linux/drivers/media/video/au0828/au0828-cards.h @@ -1,7 +1,7 @@ /* * Driver for the Auvitek USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/video/au0828/au0828-core.c b/linux/drivers/media/video/au0828/au0828-core.c index 123422f82..59dcb3255 100644 --- a/linux/drivers/media/video/au0828/au0828-core.c +++ b/linux/drivers/media/video/au0828/au0828-core.c @@ -1,7 +1,7 @@ /* * Driver for the Auvitek USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -253,5 +253,5 @@ module_init(au0828_init); module_exit(au0828_exit); MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products"); -MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>"); +MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/au0828/au0828-dvb.c b/linux/drivers/media/video/au0828/au0828-dvb.c index 1fa77ba11..ef088bc12 100644 --- a/linux/drivers/media/video/au0828/au0828-dvb.c +++ b/linux/drivers/media/video/au0828/au0828-dvb.c @@ -1,7 +1,7 @@ /* * Driver for the Auvitek USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/video/au0828/au0828-i2c.c b/linux/drivers/media/video/au0828/au0828-i2c.c index 32858dceb..03b797b9b 100644 --- a/linux/drivers/media/video/au0828/au0828-i2c.c +++ b/linux/drivers/media/video/au0828/au0828-i2c.c @@ -1,7 +1,7 @@ /* * Driver for the Auvitek AU0828 USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/video/au0828/au0828-reg.h b/linux/drivers/media/video/au0828/au0828-reg.h index 398275508..1e87fa0c6 100644 --- a/linux/drivers/media/video/au0828/au0828-reg.h +++ b/linux/drivers/media/video/au0828/au0828-reg.h @@ -1,7 +1,7 @@ /* * Driver for the Auvitek USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/video/au0828/au0828.h b/linux/drivers/media/video/au0828/au0828.h index 7beb57179..4f10ff300 100644 --- a/linux/drivers/media/video/au0828/au0828.h +++ b/linux/drivers/media/video/au0828/au0828.h @@ -1,7 +1,7 @@ /* * Driver for the Auvitek AU0828 USB bridge * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/video/bt856.c b/linux/drivers/media/video/bt856.c index 50ca987ad..e31c9d4b9 100644 --- a/linux/drivers/media/video/bt856.c +++ b/linux/drivers/media/video/bt856.c @@ -69,8 +69,8 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)"); /* ----------------------------------------------------------------------- */ -#define REG_OFFSET 0xDA -#define BT856_NR_REG 6 +#define BT856_REG_OFFSET 0xDA +#define BT856_NR_REG 6 struct bt856 { unsigned char reg[BT856_NR_REG]; @@ -90,7 +90,7 @@ bt856_write (struct i2c_client *client, { struct bt856 *encoder = i2c_get_clientdata(client); - encoder->reg[reg - REG_OFFSET] = value; + encoder->reg[reg - BT856_REG_OFFSET] = value; return i2c_smbus_write_byte_data(client, reg, value); } @@ -104,7 +104,7 @@ bt856_setbit (struct i2c_client *client, return bt856_write(client, reg, (encoder-> - reg[reg - REG_OFFSET] & ~(1 << bit)) | + reg[reg - BT856_REG_OFFSET] & ~(1 << bit)) | (value ? (1 << bit) : 0)); } diff --git a/linux/drivers/media/video/bt8xx/bttv-cards.c b/linux/drivers/media/video/bt8xx/bttv-cards.c index bf3339436..d67e127f1 100644 --- a/linux/drivers/media/video/bt8xx/bttv-cards.c +++ b/linux/drivers/media/video/bt8xx/bttv-cards.c @@ -3201,8 +3201,9 @@ static void identify_by_eeprom(struct bttv *btv, unsigned char eeprom_data[256]) static void flyvideo_gpio(struct bttv *btv) { - int gpio,has_remote,has_radio,is_capture_only,is_lr90,has_tda9820_tda9821; - int tuner=UNSET,ttype; + int gpio, has_remote, has_radio, is_capture_only; + int is_lr90, has_tda9820_tda9821; + int tuner_type = UNSET, ttype; gpio_inout(0xffffff, 0); udelay(8); /* without this we would see the 0x1800 mask */ @@ -3220,20 +3221,26 @@ static void flyvideo_gpio(struct bttv *btv) * xxxF00(LR26/LR50), xxxFE0(LR90): Remote control chip (LVA001 or CF45) soldered * Note: Some bits are Audio_Mask ! */ - ttype=(gpio&0x0f0000)>>16; - switch(ttype) { - case 0x0: tuner=2; /* NTSC, e.g. TPI8NSR11P */ + ttype = (gpio & 0x0f0000) >> 16; + switch (ttype) { + case 0x0: + tuner_type = 2; /* NTSC, e.g. TPI8NSR11P */ break; - case 0x2: tuner=39;/* LG NTSC (newer TAPC series) TAPC-H701P */ + case 0x2: + tuner_type = 39; /* LG NTSC (newer TAPC series) TAPC-H701P */ break; - case 0x4: tuner=5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */ + case 0x4: + tuner_type = 5; /* Philips PAL TPI8PSB02P, TPI8PSB12P, TPI8PSB12D or FI1216, FM1216 */ break; - case 0x6: tuner=37;/* LG PAL (newer TAPC series) TAPC-G702P */ + case 0x6: + tuner_type = 37; /* LG PAL (newer TAPC series) TAPC-G702P */ break; - case 0xC: tuner=3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ + case 0xC: + tuner_type = 3; /* Philips SECAM(+PAL) FQ1216ME or FI1216MF */ break; default: printk(KERN_INFO "bttv%d: FlyVideo_gpio: unknown tuner type.\n", btv->c.nr); + break; } has_remote = gpio & 0x800000; @@ -3246,23 +3253,26 @@ static void flyvideo_gpio(struct bttv *btv) /* * gpio & 0x001000 output bit for audio routing */ - if(is_capture_only) - tuner = TUNER_ABSENT; /* No tuner present */ + if (is_capture_only) + tuner_type = TUNER_ABSENT; /* No tuner present */ printk(KERN_INFO "bttv%d: FlyVideo Radio=%s RemoteControl=%s Tuner=%d gpio=0x%06x\n", - btv->c.nr, has_radio? "yes":"no ", has_remote? "yes":"no ", tuner, gpio); + btv->c.nr, has_radio ? "yes" : "no ", + has_remote ? "yes" : "no ", tuner_type, gpio); printk(KERN_INFO "bttv%d: FlyVideo LR90=%s tda9821/tda9820=%s capture_only=%s\n", - btv->c.nr, is_lr90?"yes":"no ", has_tda9820_tda9821?"yes":"no ", - is_capture_only?"yes":"no "); + btv->c.nr, is_lr90 ? "yes" : "no ", + has_tda9820_tda9821 ? "yes" : "no ", + is_capture_only ? "yes" : "no "); - if (tuner != UNSET) /* only set if known tuner autodetected, else let insmod option through */ - btv->tuner_type = tuner; + if (tuner_type != UNSET) /* only set if known tuner autodetected, else let insmod option through */ + btv->tuner_type = tuner_type; btv->has_radio = has_radio; /* LR90 Audio Routing is done by 2 hef4052, so Audio_Mask has 4 bits: 0x001c80 * LR26/LR50 only has 1 hef4052, Audio_Mask 0x000c00 * Audio options: from tuner, from tda9821/tda9821(mono,stereo,sap), from tda9874, ext., mute */ - if(has_tda9820_tda9821) btv->audio_mode_gpio = lt9415_audio; + if (has_tda9820_tda9821) + btv->audio_mode_gpio = lt9415_audio; /* todo: if(has_tda9874) btv->audio_mode_gpio = fv2000s_audio; */ } @@ -4036,7 +4046,7 @@ static int tuner_1_table[] = { static void __devinit avermedia_eeprom(struct bttv *btv) { - int tuner_make,tuner_tv_fm,tuner_format,tuner=0; + int tuner_make, tuner_tv_fm, tuner_format, tuner_type = 0; tuner_make = (eeprom_data[0x41] & 0x7); tuner_tv_fm = (eeprom_data[0x41] & 0x18) >> 3; @@ -4044,24 +4054,24 @@ static void __devinit avermedia_eeprom(struct bttv *btv) btv->has_remote = (eeprom_data[0x42] & 0x01); if (tuner_make == 0 || tuner_make == 2) - if(tuner_format <=0x0a) - tuner = tuner_0_table[tuner_format]; + if (tuner_format <= 0x0a) + tuner_type = tuner_0_table[tuner_format]; if (tuner_make == 1) - if(tuner_format <=9) - tuner = tuner_1_table[tuner_format]; + if (tuner_format <= 9) + tuner_type = tuner_1_table[tuner_format]; if (tuner_make == 4) - if(tuner_format == 0x09) - tuner = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ + if (tuner_format == 0x09) + tuner_type = TUNER_LG_NTSC_NEW_TAPC; /* TAPC-G702P */ printk(KERN_INFO "bttv%d: Avermedia eeprom[0x%02x%02x]: tuner=", - btv->c.nr,eeprom_data[0x41],eeprom_data[0x42]); - if(tuner) { - btv->tuner_type=tuner; - printk("%d",tuner); + btv->c.nr, eeprom_data[0x41], eeprom_data[0x42]); + if (tuner_type) { + btv->tuner_type = tuner_type; + printk(KERN_CONT "%d", tuner_type); } else - printk("Unknown type"); - printk(" radio:%s remote control:%s\n", + printk(KERN_CONT "Unknown type"); + printk(KERN_CONT " radio:%s remote control:%s\n", tuner_tv_fm ? "yes" : "no", btv->has_remote ? "yes" : "no"); } @@ -4103,7 +4113,8 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin) gpio_inout(mask,mask); gpio_bits(mask,0); - udelay(2500); + mdelay(2); + udelay(500); gpio_bits(mask,mask); if (bttv_gpio) diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c index 012eeba5e..1c8183c2c 100644 --- a/linux/drivers/media/video/bt8xx/bttv-driver.c +++ b/linux/drivers/media/video/bt8xx/bttv-driver.c @@ -96,7 +96,6 @@ static unsigned int irq_iswitch; static unsigned int uv_ratio = 50; static unsigned int full_luma_range; static unsigned int coring; -extern int no_overlay; /* API features (turn on/off stuff for testing) */ static unsigned int v4l2 = 1; @@ -1388,7 +1387,7 @@ static void init_irqreg(struct bttv *btv) (btv->gpioirq ? BT848_INT_GPINT : 0) | BT848_INT_SCERR | (fdsr ? BT848_INT_FDSR : 0) | - BT848_INT_RISCI|BT848_INT_OCERR|BT848_INT_VPRES| + BT848_INT_RISCI | BT848_INT_OCERR | BT848_INT_FMTCHG|BT848_INT_HLOCK| BT848_INT_I2CDONE, BT848_INT_MASK); diff --git a/linux/drivers/media/video/bt8xx/bttv-risc.c b/linux/drivers/media/video/bt8xx/bttv-risc.c index 0cffd3a72..310924f77 100644 --- a/linux/drivers/media/video/bt8xx/bttv-risc.c +++ b/linux/drivers/media/video/bt8xx/bttv-risc.c @@ -244,7 +244,8 @@ bttv_risc_overlay(struct bttv *btv, struct btcx_riscmem *risc, const struct bttv_format *fmt, struct bttv_overlay *ov, int skip_even, int skip_odd) { - int dwords,rc,line,maxy,start,end,skip,nskips; + int dwords, rc, line, maxy, start, end; + unsigned skip, nskips; struct btcx_skiplist *skips; __le32 *rp; u32 ri,ra; diff --git a/linux/drivers/media/video/bt8xx/bttvp.h b/linux/drivers/media/video/bt8xx/bttvp.h index 63d1d4451..403695f9a 100644 --- a/linux/drivers/media/video/bt8xx/bttvp.h +++ b/linux/drivers/media/video/bt8xx/bttvp.h @@ -269,6 +269,11 @@ int bttv_sub_add_device(struct bttv_core *core, char *name); int bttv_sub_del_devices(struct bttv_core *core); /* ---------------------------------------------------------- */ +/* bttv-cards.c */ + +extern int no_overlay; + +/* ---------------------------------------------------------- */ /* bttv-driver.c */ /* insmod options */ diff --git a/linux/drivers/media/video/btcx-risc.c b/linux/drivers/media/video/btcx-risc.c index 3a935fbc3..1c2413571 100644 --- a/linux/drivers/media/video/btcx-risc.c +++ b/linux/drivers/media/video/btcx-risc.c @@ -185,12 +185,12 @@ btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) } void -btcx_calc_skips(int line, int width, unsigned int *maxy, +btcx_calc_skips(int line, int width, int *maxy, struct btcx_skiplist *skips, unsigned int *nskips, const struct v4l2_clip *clips, unsigned int nclips) { unsigned int clip,skip; - int end,maxline; + int end, maxline; skip=0; maxline = 9999; diff --git a/linux/drivers/media/video/btcx-risc.h b/linux/drivers/media/video/btcx-risc.h index 861bc8112..f8bc6e8e7 100644 --- a/linux/drivers/media/video/btcx-risc.h +++ b/linux/drivers/media/video/btcx-risc.h @@ -23,7 +23,7 @@ int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win, int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask); void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips); -void btcx_calc_skips(int line, int width, unsigned int *maxy, +void btcx_calc_skips(int line, int width, int *maxy, struct btcx_skiplist *skips, unsigned int *nskips, const struct v4l2_clip *clips, unsigned int nclips); diff --git a/linux/drivers/media/video/bw-qcam.c b/linux/drivers/media/video/bw-qcam.c index 393113875..ca8fabdf3 100644 --- a/linux/drivers/media/video/bw-qcam.c +++ b/linux/drivers/media/video/bw-qcam.c @@ -895,10 +895,27 @@ static ssize_t qcam_read(struct file *file, char __user *buf, return len; } +static int qcam_exclusive_open(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct qcam_device *qcam = (struct qcam_device *)dev; + + return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0; +} + +static int qcam_exclusive_release(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct qcam_device *qcam = (struct qcam_device *)dev; + + clear_bit(0, &qcam->in_use); + return 0; +} + static const struct file_operations qcam_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = qcam_exclusive_open, + .release = qcam_exclusive_release, .ioctl = qcam_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -910,6 +927,7 @@ static struct video_device qcam_template= { .name = "Connectix Quickcam", .fops = &qcam_fops, + .release = video_device_release_empty, }; #define MAX_CAMS 4 @@ -947,8 +965,7 @@ static int init_bwqcam(struct parport *port) printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name); - if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1) - { + if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { parport_unregister_device(qcam->pdev); kfree(qcam); return -ENODEV; diff --git a/linux/drivers/media/video/bw-qcam.h b/linux/drivers/media/video/bw-qcam.h index 6701dafbc..8a60c5de0 100644 --- a/linux/drivers/media/video/bw-qcam.h +++ b/linux/drivers/media/video/bw-qcam.h @@ -65,4 +65,5 @@ struct qcam_device { int top, left; int status; unsigned int saved_bits; + unsigned long in_use; }; diff --git a/linux/drivers/media/video/c-qcam.c b/linux/drivers/media/video/c-qcam.c index fe8937ed1..ba4d43b90 100644 --- a/linux/drivers/media/video/c-qcam.c +++ b/linux/drivers/media/video/c-qcam.c @@ -52,6 +52,7 @@ struct qcam_device { int contrast, brightness, whitebal; int top, left; unsigned int bidirectional; + unsigned long in_use; struct mutex lock; }; @@ -688,11 +689,28 @@ static ssize_t qcam_read(struct file *file, char __user *buf, return len; } +static int qcam_exclusive_open(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct qcam_device *qcam = (struct qcam_device *)dev; + + return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0; +} + +static int qcam_exclusive_release(struct inode *inode, struct file *file) +{ + struct video_device *dev = video_devdata(file); + struct qcam_device *qcam = (struct qcam_device *)dev; + + clear_bit(0, &qcam->in_use); + return 0; +} + /* video device template */ static const struct file_operations qcam_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = qcam_exclusive_open, + .release = qcam_exclusive_release, .ioctl = qcam_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -705,6 +723,7 @@ static struct video_device qcam_template= { .name = "Colour QuickCam", .fops = &qcam_fops, + .release = video_device_release_empty, }; /* Initialize the QuickCam driver control structure. */ @@ -788,8 +807,7 @@ static int init_cqcam(struct parport *port) parport_release(qcam->pdev); - if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1) - { + if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { printk(KERN_ERR "Unable to register Colour QuickCam on %s\n", qcam->pport->name); parport_unregister_device(qcam->pdev); diff --git a/linux/drivers/media/video/cpia.c b/linux/drivers/media/video/cpia.c index 21c1f4dbb..0bee440ab 100644 --- a/linux/drivers/media/video/cpia.c +++ b/linux/drivers/media/video/cpia.c @@ -44,6 +44,7 @@ #endif #include "cpia.h" +#include "compat.h" static int video_nr = -1; @@ -3155,7 +3156,7 @@ static void put_cam(struct cpia_camera_ops* ops) static int cpia_open(struct inode *inode, struct file *file) { struct video_device *dev = video_devdata(file); - struct cam_data *cam = dev->priv; + struct cam_data *cam = video_get_drvdata(dev); int err; if (!cam) { @@ -3202,7 +3203,7 @@ static int cpia_open(struct inode *inode, struct file *file) /* Set ownership of /proc/cpia/videoX to current user */ if(cam->proc_entry) - cam->proc_entry->uid = current->uid; + cam->proc_entry->uid = current_uid(); /* set mark for loading first frame uncompressed */ cam->first_frame = 1; @@ -3232,7 +3233,7 @@ static int cpia_open(struct inode *inode, struct file *file) static int cpia_close(struct inode *inode, struct file *file) { struct video_device *dev = file->private_data; - struct cam_data *cam = dev->priv; + struct cam_data *cam = video_get_drvdata(dev); if (cam->ops) { /* Return ownership of /proc/cpia/videoX to root */ @@ -3284,7 +3285,7 @@ static ssize_t cpia_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct video_device *dev = file->private_data; - struct cam_data *cam = dev->priv; + struct cam_data *cam = video_get_drvdata(dev); int err; /* make this _really_ smp and multithread-safe */ @@ -3341,7 +3342,7 @@ static int cpia_do_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, void *arg) { struct video_device *dev = file->private_data; - struct cam_data *cam = dev->priv; + struct cam_data *cam = video_get_drvdata(dev); int retval = 0; if (!cam || !cam->ops) @@ -3739,7 +3740,7 @@ static int cpia_mmap(struct file *file, struct vm_area_struct *vma) unsigned long start = vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start; unsigned long page, pos; - struct cam_data *cam = dev->priv; + struct cam_data *cam = video_get_drvdata(dev); int retval; if (!cam || !cam->ops) @@ -3801,6 +3802,7 @@ static const struct file_operations cpia_fops = { static struct video_device cpia_template = { .name = "CPiA Camera", .fops = &cpia_fops, + .release = video_device_release_empty, }; /* initialise cam_data structure */ @@ -3928,7 +3930,7 @@ static void init_camera_struct(struct cam_data *cam, cam->proc_entry = NULL; memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template)); - cam->vdev.priv = cam; + video_set_drvdata(&cam->vdev, cam); cam->curframe = 0; for (i = 0; i < FRAME_NUM; i++) { @@ -3955,7 +3957,7 @@ struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowleve camera->lowlevel_data = lowlevel; /* register v4l device */ - if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { kfree(camera); printk(KERN_DEBUG "video_register_device failed\n"); return NULL; diff --git a/linux/drivers/media/video/cpia2/cpia2_core.c b/linux/drivers/media/video/cpia2/cpia2_core.c index ce43a054a..8e55d3a21 100644 --- a/linux/drivers/media/video/cpia2/cpia2_core.c +++ b/linux/drivers/media/video/cpia2/cpia2_core.c @@ -1563,7 +1563,7 @@ static int config_sensor_500(struct camera_data *cam, * * This sets all user changeable properties to the values in cam->params. *****************************************************************************/ -int set_all_properties(struct camera_data *cam) +static int set_all_properties(struct camera_data *cam) { /** * Don't set target_kb here, it will be set later. @@ -1614,7 +1614,7 @@ void cpia2_save_camera_state(struct camera_data *cam) * get_color_params * *****************************************************************************/ -void get_color_params(struct camera_data *cam) +static void get_color_params(struct camera_data *cam) { cpia2_do_command(cam, CPIA2_CMD_GET_VP_BRIGHTNESS, TRANSFER_READ, 0); cpia2_do_command(cam, CPIA2_CMD_GET_VP_SATURATION, TRANSFER_READ, 0); @@ -1907,7 +1907,7 @@ void cpia2_set_saturation(struct camera_data *cam, unsigned char value) * wake_system * *****************************************************************************/ -void wake_system(struct camera_data *cam) +static void wake_system(struct camera_data *cam) { cpia2_do_command(cam, CPIA2_CMD_SET_WAKEUP, TRANSFER_WRITE, 0); } @@ -1918,7 +1918,7 @@ void wake_system(struct camera_data *cam) * * Valid for STV500 sensor only *****************************************************************************/ -void set_lowlight_boost(struct camera_data *cam) +static void set_lowlight_boost(struct camera_data *cam) { struct cpia2_command cmd; @@ -2195,7 +2195,7 @@ void cpia2_dbg_dump_registers(struct camera_data *cam) * * Sets all values to the defaults *****************************************************************************/ -void reset_camera_struct(struct camera_data *cam) +static void reset_camera_struct(struct camera_data *cam) { /*** * The following parameter values are the defaults from the register map. diff --git a/linux/drivers/media/video/cpia2/cpia2_usb.c b/linux/drivers/media/video/cpia2/cpia2_usb.c index 01131e984..bd9277873 100644 --- a/linux/drivers/media/video/cpia2/cpia2_usb.c +++ b/linux/drivers/media/video/cpia2/cpia2_usb.c @@ -486,7 +486,7 @@ int cpia2_usb_change_streaming_alternate(struct camera_data *cam, * set_alternate * *****************************************************************************/ -int set_alternate(struct camera_data *cam, unsigned int alt) +static int set_alternate(struct camera_data *cam, unsigned int alt) { int ret = 0; @@ -640,7 +640,7 @@ int cpia2_usb_transfer_cmd(struct camera_data *cam, static int submit_urbs(struct camera_data *cam) { struct urb *urb; - int fx, err, i; + int fx, err, i, j; for(i=0; i<NUM_SBUF; ++i) { if (cam->sbuf[i].data) @@ -665,6 +665,9 @@ static int submit_urbs(struct camera_data *cam) } urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); if (!urb) { + ERR("%s: usb_alloc_urb error!\n", __func__); + for (j = 0; j < i; j++) + usb_free_urb(cam->sbuf[j].urb); return -ENOMEM; } diff --git a/linux/drivers/media/video/cpia2/cpia2_v4l.c b/linux/drivers/media/video/cpia2/cpia2_v4l.c index 515c8b57a..897e8d1a5 100644 --- a/linux/drivers/media/video/cpia2/cpia2_v4l.c +++ b/linux/drivers/media/video/cpia2/cpia2_v4l.c @@ -241,8 +241,7 @@ static struct v4l2_queryctrl controls[] = { *****************************************************************************/ static int cpia2_open(struct inode *inode, struct file *file) { - struct video_device *dev = video_devdata(file); - struct camera_data *cam = video_get_drvdata(dev); + struct camera_data *cam = video_drvdata(file); int retval = 0; if (!cam) { @@ -357,8 +356,7 @@ static int cpia2_close(struct inode *inode, struct file *file) static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, loff_t *off) { - struct video_device *dev = video_devdata(file); - struct camera_data *cam = video_get_drvdata(dev); + struct camera_data *cam = video_drvdata(file); int noblock = file->f_flags&O_NONBLOCK; struct cpia2_fh *fh = file->private_data; @@ -382,9 +380,7 @@ static ssize_t cpia2_v4l_read(struct file *file, char __user *buf, size_t count, *****************************************************************************/ static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *wait) { - struct video_device *dev = video_devdata(filp); - struct camera_data *cam = video_get_drvdata(dev); - + struct camera_data *cam = video_drvdata(filp); struct cpia2_fh *fh = filp->private_data; if(!cam) @@ -1024,7 +1020,6 @@ static int ioctl_queryctrl(void *arg,struct camera_data *cam) if(cam->params.pnp_id.device_type == DEVICE_STV_672 && cam->params.version.sensor_flags==CPIA2_VP_SENSOR_FLAGS_500){ // Maximum 15fps - int i; for(i=0; i<c->maximum; ++i) { if(framerate_controls[i].value == CPIA2_VP_FRAMERATE_15) { @@ -1580,8 +1575,7 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file) static int cpia2_do_ioctl(struct inode *inode, struct file *file, unsigned int ioctl_nr, void *arg) { - struct video_device *dev = video_devdata(file); - struct camera_data *cam = video_get_drvdata(dev); + struct camera_data *cam = video_drvdata(file); int retval = 0; if (!cam) @@ -1861,9 +1855,8 @@ static int cpia2_ioctl(struct inode *inode, struct file *file, *****************************************************************************/ static int cpia2_mmap(struct file *file, struct vm_area_struct *area) { + struct camera_data *cam = video_drvdata(file); int retval; - struct video_device *dev = video_devdata(file); - struct camera_data *cam = video_get_drvdata(dev); /* Priority check */ struct cpia2_fh *fh = file->private_data; @@ -1959,8 +1952,7 @@ int cpia2_register_camera(struct camera_data *cam) reset_camera_struct_v4l(cam); /* register v4l device */ - if (video_register_device - (cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + if (video_register_device(cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { ERR("video_register_device failed\n"); video_device_release(cam->vdev); return -ENODEV; diff --git a/linux/drivers/media/video/cs5345.c b/linux/drivers/media/video/cs5345.c index e4c505d2f..decbc5f1f 100644 --- a/linux/drivers/media/video/cs5345.c +++ b/linux/drivers/media/video/cs5345.c @@ -36,7 +36,7 @@ static int debug; module_param(debug, bool, 0644); -MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On"); +MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On"); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) static unsigned short normal_i2c[] = { 0x98 >> 1, I2C_CLIENT_END }; diff --git a/linux/drivers/media/video/cs53l32a.c b/linux/drivers/media/video/cs53l32a.c index f5ea3f4a9..68f31270c 100644 --- a/linux/drivers/media/video/cs53l32a.c +++ b/linux/drivers/media/video/cs53l32a.c @@ -40,7 +40,7 @@ static int debug; module_param(debug, bool, 0644); -MODULE_PARM_DESC(debug, "Debugging messages\n\t\t\t0=Off (default), 1=On"); +MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On"); static unsigned short normal_i2c[] = { 0x22 >> 1, I2C_CLIENT_END }; diff --git a/linux/drivers/media/video/cx18/cx18-av-firmware.c b/linux/drivers/media/video/cx18/cx18-av-firmware.c index 9e7c20c78..0488b6297 100644 --- a/linux/drivers/media/video/cx18/cx18-av-firmware.c +++ b/linux/drivers/media/video/cx18/cx18-av-firmware.c @@ -33,7 +33,7 @@ int cx18_av_loadfw(struct cx18 *cx) u32 v; const u8 *ptr; int i; - int retries = 0; + int retries1 = 0; if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) { CX18_ERR("unable to open firmware %s\n", FWFILE); @@ -42,7 +42,7 @@ int cx18_av_loadfw(struct cx18 *cx) /* The firmware load often has byte errors, so allow for several retries, both at byte level and at the firmware load level. */ - while (retries < 5) { + while (retries1 < 5) { cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000); cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); @@ -58,9 +58,9 @@ int cx18_av_loadfw(struct cx18 *cx) for (i = 0; i < size; i++) { u32 dl_control = 0x0F000000 | i | ((u32)ptr[i] << 16); u32 value = 0; - int retries; + int retries2; - for (retries = 0; retries < 5; retries++) { + for (retries2 = 0; retries2 < 5; retries2++) { cx18_av_write4(cx, CXADEC_DL_CTL, dl_control); udelay(10); value = cx18_av_read4(cx, CXADEC_DL_CTL); @@ -70,18 +70,18 @@ int cx18_av_loadfw(struct cx18 *cx) the address. We can only write the lower address byte of the address. */ if ((value & 0x3F00) != (dl_control & 0x3F00)) { - retries = 5; + retries2 = 5; break; } } - if (retries >= 5) + if (retries2 >= 5) break; } if (i == size) break; - retries++; + retries1++; } - if (retries >= 5) { + if (retries1 >= 5) { CX18_ERR("unable to load firmware %s\n", FWFILE); release_firmware(fw); return -EIO; diff --git a/linux/drivers/media/video/cx18/cx18-driver.c b/linux/drivers/media/video/cx18/cx18-driver.c index de2e7bc98..202b28190 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.c +++ b/linux/drivers/media/video/cx18/cx18-driver.c @@ -79,9 +79,9 @@ static int mmio_ndelay[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; -static int cardtype_c = 1; -static int tuner_c = 1; -static int radio_c = 1; +static unsigned cardtype_c = 1; +static unsigned tuner_c = 1; +static unsigned radio_c = 1; static int mmio_ndelay_c = 1; static char pal[] = "--"; static char secam[] = "--"; @@ -412,9 +412,9 @@ done: if (cx->card == NULL) { cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); - CX18_ERR("Unknown card: vendor/device: %04x/%04x\n", + CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n", cx->dev->vendor, cx->dev->device); - CX18_ERR(" subsystem vendor/device: %04x/%04x\n", + CX18_ERR(" subsystem vendor/device: [%04x:%04x]\n", cx->dev->subsystem_vendor, cx->dev->subsystem_device); CX18_ERR("Defaulting to %s card\n", cx->card->name); CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n"); diff --git a/linux/drivers/media/video/cx18/cx18-driver.h b/linux/drivers/media/video/cx18/cx18-driver.h index 6ac412a97..cc6f288a6 100644 --- a/linux/drivers/media/video/cx18/cx18-driver.h +++ b/linux/drivers/media/video/cx18/cx18-driver.h @@ -38,7 +38,6 @@ #include <linux/i2c-algo-bit.h> #include <linux/list.h> #include <linux/unistd.h> -#include <linux/byteorder/swab.h> #include <linux/pagemap.h> #include <linux/workqueue.h> #include <linux/mutex.h> diff --git a/linux/drivers/media/video/cx18/cx18-dvb.c b/linux/drivers/media/video/cx18/cx18-dvb.c index 358a39864..afc694e7b 100644 --- a/linux/drivers/media/video/cx18/cx18-dvb.c +++ b/linux/drivers/media/video/cx18/cx18-dvb.c @@ -1,7 +1,7 @@ /* * cx18 functions for DVB support * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/video/cx18/cx18-dvb.h b/linux/drivers/media/video/cx18/cx18-dvb.h index d6a6ccda7..bf8d8f6f5 100644 --- a/linux/drivers/media/video/cx18/cx18-dvb.h +++ b/linux/drivers/media/video/cx18/cx18-dvb.h @@ -1,7 +1,7 @@ /* * cx18 functions for DVB support * - * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2008 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/video/cx18/cx18-i2c.c b/linux/drivers/media/video/cx18/cx18-i2c.c index 73e7e3a2e..f28a1ff2e 100644 --- a/linux/drivers/media/video/cx18/cx18-i2c.c +++ b/linux/drivers/media/video/cx18/cx18-i2c.c @@ -28,8 +28,6 @@ #include "cx18-av-core.h" #include "cx18-i2c.h" -#include <media/ir-kbd-i2c.h> - #define CX18_REG_I2C_1_WR 0xf15000 #define CX18_REG_I2C_1_RD 0xf15008 #define CX18_REG_I2C_2_WR 0xf25100 diff --git a/linux/drivers/media/video/cx18/cx18-queue.c b/linux/drivers/media/video/cx18/cx18-queue.c index 78a0f04be..a33ba04a2 100644 --- a/linux/drivers/media/video/cx18/cx18-queue.c +++ b/linux/drivers/media/video/cx18/cx18-queue.c @@ -143,10 +143,10 @@ int cx18_stream_alloc(struct cx18_stream *s) s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024); - if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] - - (char *)cx->scb) > SCB_RESERVED_SIZE) { - unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE - - ((char *)cx->scb->cpu_mdl)); + if (((char __iomem *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] - + (char __iomem *)cx->scb) > SCB_RESERVED_SIZE) { + unsigned bufsz = (((char __iomem *)cx->scb) + SCB_RESERVED_SIZE - + ((char __iomem *)cx->scb->cpu_mdl)); CX18_ERR("Too many buffers, cannot fit in SCB area\n"); CX18_ERR("Max buffers = %zd\n", diff --git a/linux/drivers/media/video/cx23885/Kconfig b/linux/drivers/media/video/cx23885/Kconfig index e60bd31b5..8c1b7fa47 100644 --- a/linux/drivers/media/video/cx23885/Kconfig +++ b/linux/drivers/media/video/cx23885/Kconfig @@ -15,6 +15,7 @@ config VIDEO_CX23885 select DVB_S5H1409 if !DVB_FE_CUSTOMISE select DVB_S5H1411 if !DVB_FE_CUSTOMISE select DVB_LGDT330X if !DVB_FE_CUSTOMISE + select DVB_ZL10353 if !DVB_FE_CUSTOMISE select MEDIA_TUNER_XC2028 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_TDA8290 if !DVB_FE_CUSTOMIZE select MEDIA_TUNER_TDA18271 if !DVB_FE_CUSTOMIZE diff --git a/linux/drivers/media/video/cx23885/cx23885-417.c b/linux/drivers/media/video/cx23885/cx23885-417.c index 106b594ed..25349f6b9 100644 --- a/linux/drivers/media/video/cx23885/cx23885-417.c +++ b/linux/drivers/media/video/cx23885/cx23885-417.c @@ -4,7 +4,7 @@ * * (c) 2004 Jelle Foks <jelle@foks.8m.com> * (c) 2004 Gerd Knorr <kraxel@bytesex.org> - * (c) 2008 Steven Toth <stoth@hauppauge.com> + * (c) 2008 Steven Toth <stoth@linuxtv.org> * - CX23885/7/8 support * * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/), @@ -632,7 +632,7 @@ int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value) /* ------------------------------------------------------------------ */ /* MPEG encoder API */ -char *cmd_to_str(int cmd) +static char *cmd_to_str(int cmd) { switch (cmd) { case CX2341X_ENC_PING_FW: diff --git a/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c index f7cb19256..be9a6d8ec 100644 --- a/linux/drivers/media/video/cx23885/cx23885-cards.c +++ b/linux/drivers/media/video/cx23885/cx23885-cards.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -155,6 +155,10 @@ struct cx23885_board cx23885_boards[] = { .portb = CX23885_MPEG_DVB, .portc = CX23885_MPEG_DVB, }, + [CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H] = { + .name = "Leadtek Winfast PxDVR3200 H", + .portc = CX23885_MPEG_DVB, + }, }; const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards); @@ -230,6 +234,10 @@ struct cx23885_subid cx23885_subids[] = { .subvendor = 0x18ac, .subdevice = 0xdb78, .card = CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP, + }, { + .subvendor = 0x107d, + .subdevice = 0x6681, + .card = CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H, }, }; const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids); @@ -349,21 +357,18 @@ int cx23885_tuner_callback(void *priv, int command, int arg) case CX23885_BOARD_HAUPPAUGE_HVR1400: case CX23885_BOARD_HAUPPAUGE_HVR1500: case CX23885_BOARD_HAUPPAUGE_HVR1500Q: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: /* Tuner Reset Command */ - if (command == 0) - bitmask = 0x04; + 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; - } + /* 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; } @@ -492,6 +497,19 @@ void cx23885_gpio_setup(struct cx23885_dev *dev) mdelay(20); cx_set(GP0_IO, 0x000f000f); break; + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + /* GPIO-2 xc3028 tuner reset */ + + /* The following GPIO's are on the internal AVCore (cx25840) */ + /* GPIO-? zl10353 demod reset */ + + /* Put the parts into reset and back */ + cx_set(GP0_IO, 0x00040000); + mdelay(20); + cx_clear(GP0_IO, 0x00000004); + mdelay(20); + cx_set(GP0_IO, 0x00040004); + break; } } @@ -579,6 +597,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1200: case CX23885_BOARD_HAUPPAUGE_HVR1700: case CX23885_BOARD_HAUPPAUGE_HVR1400: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: default: ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */ @@ -592,6 +611,7 @@ void cx23885_card_setup(struct cx23885_dev *dev) case CX23885_BOARD_HAUPPAUGE_HVR1800: case CX23885_BOARD_HAUPPAUGE_HVR1800lp: case CX23885_BOARD_HAUPPAUGE_HVR1700: + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: request_module("cx25840"); break; } diff --git a/linux/drivers/media/video/cx23885/cx23885-core.c b/linux/drivers/media/video/cx23885/cx23885-core.c index 0c34db9f7..c050cd2ce 100644 --- a/linux/drivers/media/video/cx23885/cx23885-core.c +++ b/linux/drivers/media/video/cx23885/cx23885-core.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,7 +34,7 @@ #include "cx23885.h" MODULE_DESCRIPTION("Driver for cx23885 based TV cards"); -MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>"); +MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); MODULE_LICENSE("GPL"); static unsigned int debug; diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c index c0c5b5be7..0d8ce96cf 100644 --- a/linux/drivers/media/video/cx23885/cx23885-dvb.c +++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -502,6 +502,32 @@ static int dvb_register(struct cx23885_tsport *port) } break; } + case CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H: + i2c_bus = &dev->i2c_bus[0]; + + 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 = &dev->i2c_bus[1].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-i2c.c b/linux/drivers/media/video/cx23885/cx23885-i2c.c index f0ee47256..6f3a43607 100644 --- a/linux/drivers/media/video/cx23885/cx23885-i2c.c +++ b/linux/drivers/media/video/cx23885/cx23885-i2c.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/video/cx23885/cx23885-reg.h b/linux/drivers/media/video/cx23885/cx23885-reg.h index bdd11bc51..20b68a236 100644 --- a/linux/drivers/media/video/cx23885/cx23885-reg.h +++ b/linux/drivers/media/video/cx23885/cx23885-reg.h @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by diff --git a/linux/drivers/media/video/cx23885/cx23885-vbi.c b/linux/drivers/media/video/cx23885/cx23885-vbi.c index a6cf4146d..4b65552b3 100644 --- a/linux/drivers/media/video/cx23885/cx23885-vbi.c +++ b/linux/drivers/media/video/cx23885/cx23885-vbi.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -86,7 +86,9 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev, return 0; } -int cx23885_stop_vbi_dma(struct cx23885_dev *dev) +#if 0 +/* not (yet) used */ +static int cx23885_stop_vbi_dma(struct cx23885_dev *dev) { /* stop dma */ cx_clear(VID_A_DMA_CTL, 0x00000022); @@ -96,8 +98,9 @@ int cx23885_stop_vbi_dma(struct cx23885_dev *dev) cx_clear(VID_A_INT_MSK, 0x00000022); return 0; } +#endif -int cx23885_restart_vbi_queue(struct cx23885_dev *dev, +static int cx23885_restart_vbi_queue(struct cx23885_dev *dev, struct cx23885_dmaqueue *q) { struct cx23885_buffer *buf; diff --git a/linux/drivers/media/video/cx23885/cx23885-video.c b/linux/drivers/media/video/cx23885/cx23885-video.c index 98a7dc1c0..70333ee2b 100644 --- a/linux/drivers/media/video/cx23885/cx23885-video.c +++ b/linux/drivers/media/video/cx23885/cx23885-video.c @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2007 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2007 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,7 +42,7 @@ #endif MODULE_DESCRIPTION("v4l2 driver module for cx23885 based TV cards"); -MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>"); +MODULE_AUTHOR("Steven Toth <stoth@linuxtv.org>"); MODULE_LICENSE("GPL"); /* ------------------------------------------------------------------ */ @@ -276,7 +276,7 @@ static struct cx23885_ctrl cx23885_ctls[] = { }; static const int CX23885_CTLS = ARRAY_SIZE(cx23885_ctls); -const u32 cx23885_user_ctrls[] = { +static const u32 cx23885_user_ctrls[] = { V4L2_CID_USER_CLASS, V4L2_CID_BRIGHTNESS, V4L2_CID_CONTRAST, @@ -289,14 +289,13 @@ const u32 cx23885_user_ctrls[] = { V4L2_CID_AUDIO_MUTE, 0 }; -EXPORT_SYMBOL(cx23885_user_ctrls); static const u32 *ctrl_classes[] = { cx23885_user_ctrls, NULL }; -void cx23885_video_wakeup(struct cx23885_dev *dev, +static void cx23885_video_wakeup(struct cx23885_dev *dev, struct cx23885_dmaqueue *q, u32 count) { struct cx23885_buffer *buf; @@ -331,7 +330,7 @@ void cx23885_video_wakeup(struct cx23885_dev *dev, __func__, bc); } -int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) +static int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) { dprintk(1, "%s(norm = 0x%08x) name: [%s]\n", __func__, @@ -349,7 +348,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm) return 0; } -struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, +static struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, struct pci_dev *pci, struct video_device *template, char *type) @@ -369,7 +368,7 @@ struct video_device *cx23885_vdev_init(struct cx23885_dev *dev, return vfd; } -int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) +static int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) { int i; @@ -386,7 +385,6 @@ int cx23885_ctrl_query(struct v4l2_queryctrl *qctrl) *qctrl = cx23885_ctls[i].v; return 0; } -EXPORT_SYMBOL(cx23885_ctrl_query); /* ------------------------------------------------------------------- */ /* resource management */ @@ -437,7 +435,7 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh, mutex_unlock(&dev->lock); } -int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) +static int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) { struct v4l2_routing route; memset(&route, 0, sizeof(route)); @@ -462,10 +460,9 @@ int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input) return 0; } -EXPORT_SYMBOL(cx23885_video_mux); /* ------------------------------------------------------------------ */ -int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, +static int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width, unsigned int height, enum v4l2_field field) { dprintk(1, "%s()\n", __func__); @@ -967,15 +964,14 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma) /* ------------------------------------------------------------------ */ /* VIDEO CTRL IOCTLS */ -int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl) +static int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl) { dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__); cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl); return 0; } -EXPORT_SYMBOL(cx23885_get_control); -int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) +static int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) { dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)" " (disabled - no action)\n", __func__); @@ -984,7 +980,6 @@ int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl) #endif return 0; } -EXPORT_SYMBOL(cx23885_set_control); static void init_controls(struct cx23885_dev *dev) { @@ -1235,7 +1230,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms) return 0; } -int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) +static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) { static const char *iname[] = { [CX23885_VMUX_COMPOSITE1] = "Composite1", @@ -1268,7 +1263,6 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i) i->std = CX23885_NORMS; return 0; } -EXPORT_SYMBOL(cx23885_enum_input); static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) @@ -1383,7 +1377,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, return 0; } -int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) +static int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) { if (unlikely(UNSET == dev->tuner_type)) return -EINVAL; @@ -1402,7 +1396,6 @@ int cx23885_set_freq(struct cx23885_dev *dev, struct v4l2_frequency *f) return 0; } -EXPORT_SYMBOL(cx23885_set_freq); static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h index 9b76a8acf..49e3eaec7 100644 --- a/linux/drivers/media/video/cx23885/cx23885.h +++ b/linux/drivers/media/video/cx23885/cx23885.h @@ -1,7 +1,7 @@ /* * Driver for the Conexant CX23885 PCIe bridge * - * Copyright (c) 2006 Steven Toth <stoth@hauppauge.com> + * Copyright (c) 2006 Steven Toth <stoth@linuxtv.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -66,6 +66,7 @@ #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 +#define CX23885_BOARD_LEADTEK_WINFAST_PXDVR3200_H 12 /* 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/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c index 7b48e0285..cb4a9c64e 100644 --- a/linux/drivers/media/video/cx25840/cx25840-core.c +++ b/linux/drivers/media/video/cx25840/cx25840-core.c @@ -13,7 +13,7 @@ * NTSC sliced VBI support by Christopher Neufeld <television@cneufeld.ca> * with additional fixes by Hans Verkuil <hverkuil@xs4all.nl>. * - * CX23885 support by Steven Toth <stoth@hauppauge.com>. + * CX23885 support by Steven Toth <stoth@linuxtv.org>. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/linux/drivers/media/video/cx88/cx88-blackbird.c b/linux/drivers/media/video/cx88/cx88-blackbird.c index 0cd510814..5f44368f6 100644 --- a/linux/drivers/media/video/cx88/cx88-blackbird.c +++ b/linux/drivers/media/video/cx88/cx88-blackbird.c @@ -1092,6 +1092,7 @@ static int mpeg_open(struct inode *inode, struct file *file) err = drv->request_acquire(drv); if(err != 0) { dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err); + unlock_kernel(); return err; } } diff --git a/linux/drivers/media/video/dabusb.c b/linux/drivers/media/video/dabusb.c index f23e6b84d..4acba6e92 100644 --- a/linux/drivers/media/video/dabusb.c +++ b/linux/drivers/media/video/dabusb.c @@ -451,6 +451,7 @@ static int dabusb_fpga_download (pdabusb_t s, const char *fname) ret = request_firmware(&fw, "dabusb/bitstream.bin", &s->usbdev->dev); if (ret) { err("Failed to load \"dabusb/bitstream.bin\": %d\n", ret); + kfree(b); return ret; } diff --git a/linux/drivers/media/video/em28xx/em28xx-audio.c b/linux/drivers/media/video/em28xx/em28xx-audio.c index 904973305..14ef4da24 100644 --- a/linux/drivers/media/video/em28xx/em28xx-audio.c +++ b/linux/drivers/media/video/em28xx/em28xx-audio.c @@ -171,8 +171,14 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) memset(dev->adev->transfer_buffer[i], 0x80, sb_size); urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC); - if (!urb) + if (!urb) { + em28xx_errdev("usb_alloc_urb failed!\n"); + for (j = 0; j < i; j++) { + usb_free_urb(dev->adev->urb[j]); + kfree(dev->adev->transfer_buffer[j]); + } return -ENOMEM; + } urb->dev = dev->udev; urb->context = dev; diff --git a/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c index 5b532ccec..79c11b1d0 100644 --- a/linux/drivers/media/video/em28xx/em28xx-dvb.c +++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c @@ -275,7 +275,7 @@ static int attach_xc3028(u8 addr, struct em28xx *dev) /* ------------------------------------------------------------------ */ -int register_dvb(struct em28xx_dvb *dvb, +static int register_dvb(struct em28xx_dvb *dvb, struct module *module, struct em28xx *dev, struct device *device) diff --git a/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c index 97853384c..2989a65f6 100644 --- a/linux/drivers/media/video/em28xx/em28xx-i2c.c +++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c @@ -143,10 +143,11 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, unsigned char addr) } for (write_timeout = EM2800_I2C_WRITE_TIMEOUT; write_timeout > 0; write_timeout -= 5) { - unsigned msg = dev->em28xx_read_reg(dev, 0x5); - if (msg == 0x94) + unsigned reg = dev->em28xx_read_reg(dev, 0x5); + + if (reg == 0x94) return -ENODEV; - else if (msg == 0x84) + else if (reg == 0x84) return 0; msleep(5); } diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h index e5e47fe66..4bdff9619 100644 --- a/linux/drivers/media/video/em28xx/em28xx.h +++ b/linux/drivers/media/video/em28xx/em28xx.h @@ -420,8 +420,8 @@ struct em28xx { /* frame properties */ int width; /* current frame width */ int height; /* current frame height */ - int hscale; /* horizontal scale factor (see datasheet) */ - int vscale; /* vertical scale factor (see datasheet) */ + unsigned hscale; /* horizontal scale factor (see datasheet) */ + unsigned vscale; /* vertical scale factor (see datasheet) */ int interlaced; /* 1=interlace fileds, 0=just top fileds */ unsigned int video_bytesread; /* Number of bytes read */ diff --git a/linux/drivers/media/video/et61x251/et61x251_core.c b/linux/drivers/media/video/et61x251/et61x251_core.c index 7d0f31db5..f58aee5aa 100644 --- a/linux/drivers/media/video/et61x251/et61x251_core.c +++ b/linux/drivers/media/video/et61x251/et61x251_core.c @@ -1218,7 +1218,7 @@ static int et61x251_open(struct inode* inode, struct file* filp) if (!down_read_trylock(&et61x251_dev_lock)) return -ERESTARTSYS; - cam = video_get_drvdata(video_devdata(filp)); + cam = video_drvdata(filp); if (wait_for_completion_interruptible(&cam->probe)) { up_read(&et61x251_dev_lock); @@ -1301,7 +1301,7 @@ static int et61x251_release(struct inode* inode, struct file* filp) down_write(&et61x251_dev_lock); - cam = video_get_drvdata(video_devdata(filp)); + cam = video_drvdata(filp); et61x251_stop_transfer(cam); et61x251_release_buffers(cam); @@ -1322,7 +1322,7 @@ static ssize_t et61x251_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) { - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); + struct et61x251_device *cam = video_drvdata(filp); struct et61x251_frame_t* f, * i; unsigned long lock_flags; long timeout; @@ -1430,7 +1430,7 @@ exit: static unsigned int et61x251_poll(struct file *filp, poll_table *wait) { - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); + struct et61x251_device *cam = video_drvdata(filp); struct et61x251_frame_t* f; unsigned long lock_flags; unsigned int mask = 0; @@ -1506,7 +1506,7 @@ static struct vm_operations_struct et61x251_vm_ops = { static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) { - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); + struct et61x251_device *cam = video_drvdata(filp); unsigned long size = vma->vm_end - vma->vm_start, start = vma->vm_start; void *pos; @@ -2399,7 +2399,7 @@ et61x251_vidioc_s_parm(struct et61x251_device* cam, void __user * arg) static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp, unsigned int cmd, void __user * arg) { - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); + struct et61x251_device *cam = video_drvdata(filp); switch (cmd) { @@ -2494,7 +2494,7 @@ static int et61x251_ioctl_v4l2(struct inode* inode, struct file* filp, static int et61x251_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg) { - struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); + struct et61x251_device *cam = video_drvdata(filp); int err = 0; if (mutex_lock_interruptible(&cam->fileop_mutex)) @@ -2592,6 +2592,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->fops = &et61x251_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; + cam->v4ldev->parent = &udev->dev; video_set_drvdata(cam->v4ldev, cam); init_completion(&cam->probe); diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c index 739ef557c..4d9f4cc25 100644 --- a/linux/drivers/media/video/gspca/conex.c +++ b/linux/drivers/media/video/gspca/conex.c @@ -124,7 +124,7 @@ static void reg_r(struct gspca_dev *gspca_dev, struct usb_device *dev = gspca_dev->dev; #ifdef GSPCA_DEBUG - if (len > sizeof gspca_dev->usb_buf) { + if (len > USB_BUF_SZ) { err("reg_r: buffer overflow"); return; } @@ -164,7 +164,7 @@ static void reg_w(struct gspca_dev *gspca_dev, struct usb_device *dev = gspca_dev->dev; #ifdef GSPCA_DEBUG - if (len > sizeof gspca_dev->usb_buf) { + if (len > USB_BUF_SZ) { err("reg_w: buffer overflow"); return; } @@ -731,13 +731,13 @@ static void cx11646_jpeg(struct gspca_dev*gspca_dev) reg_w_val(gspca_dev, 0x0000, 0x00); /* wait for completion */ retry = 50; - while (retry--) { + do { reg_r(gspca_dev, 0x0002, 1); /* 0x07 until 0x00 */ if (gspca_dev->usb_buf[0] == 0x00) break; reg_w_val(gspca_dev, 0x0053, 0x00); - } + } while (--retry); if (retry == 0) PDEBUG(D_ERR, "Damned Errors sending jpeg Table"); /* send the qtable now */ @@ -826,8 +826,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { cx11646_init1(gspca_dev); cx11646_initsize(gspca_dev); @@ -845,10 +845,6 @@ static void sd_start(struct gspca_dev *gspca_dev) cx11646_jpeg(gspca_dev); } -static void sd_stopN(struct gspca_dev *gspca_dev) -{ -} - static void sd_stop0(struct gspca_dev *gspca_dev) { int retry = 50; @@ -871,10 +867,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev) reg_w_val(gspca_dev, 0x00fc, 0xe0); } -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -998,11 +990,9 @@ static struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, - .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; diff --git a/linux/drivers/media/video/gspca/etoms.c b/linux/drivers/media/video/gspca/etoms.c index 626d03e17..86f3932c2 100644 --- a/linux/drivers/media/video/gspca/etoms.c +++ b/linux/drivers/media/video/gspca/etoms.c @@ -81,6 +81,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setcontrast, .get = sd_getcontrast, }, +#define COLOR_IDX 2 { { .id = V4L2_CID_SATURATION, @@ -234,7 +235,7 @@ static void reg_r(struct gspca_dev *gspca_dev, struct usb_device *dev = gspca_dev->dev; #ifdef GSPCA_DEBUG - if (len > sizeof gspca_dev->usb_buf) { + if (len > USB_BUF_SZ) { err("reg_r: buffer overflow"); return; } @@ -272,7 +273,7 @@ static void reg_w(struct gspca_dev *gspca_dev, struct usb_device *dev = gspca_dev->dev; #ifdef GSPCA_DEBUG - if (len > sizeof gspca_dev->usb_buf) { + if (len > USB_BUF_SZ) { err("reg_w: buffer overflow"); return; } @@ -665,6 +666,7 @@ static int sd_config(struct gspca_dev *gspca_dev, } else { cam->cam_mode = vga_mode; cam->nmodes = sizeof vga_mode / sizeof vga_mode[0]; + gspca_dev->ctrl_dis = (1 << COLOR_IDX); } sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; @@ -674,8 +676,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -709,14 +711,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) et_video(gspca_dev, 0); /* video off */ } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static __u8 Et_getgainG(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -899,11 +893,9 @@ static struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, }; @@ -911,7 +903,7 @@ static struct sd_desc sd_desc = { /* -- module initialisation -- */ static __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106}, -#ifndef CONFIG_USB_ET61X251 +#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE {USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX}, #endif {} diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c index df7c5cb0a..122644224 100644 --- a/linux/drivers/media/video/gspca/gspca.c +++ b/linux/drivers/media/video/gspca/gspca.c @@ -118,7 +118,9 @@ static void fill_frame(struct gspca_dev *gspca_dev, cam_pkt_op pkt_scan; if (urb->status != 0) { +#ifdef CONFIG_PM if (!gspca_dev->frozen) +#endif PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); return; /* disconnection ? */ } @@ -183,6 +185,51 @@ static void isoc_irq(struct urb *urb } /* + * bulk message interrupt from the USB device + */ +static void bulk_irq(struct urb *urb +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) + , struct pt_regs *regs +#endif +) +{ + struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; + struct gspca_frame *frame; + int j, ret; + + PDEBUG(D_PACK, "bulk irq"); + if (!gspca_dev->streaming) + return; + if (urb->status != 0 && urb->status != -ECONNRESET) { +#ifdef CONFIG_PM + if (!gspca_dev->frozen) +#endif + PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status); + return; /* disconnection ? */ + } + + /* check the availability of the frame buffer */ + j = gspca_dev->fr_i; + j = gspca_dev->fr_queue[j]; + frame = &gspca_dev->frame[j]; + if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS) + != V4L2_BUF_FLAG_QUEUED) { + gspca_dev->last_packet_type = DISCARD_PACKET; + } else { + PDEBUG(D_PACK, "packet l:%d", urb->actual_length); + gspca_dev->sd_desc->pkt_scan(gspca_dev, + frame, + urb->transfer_buffer, + urb->actual_length); + } + /* resubmit the URB */ + urb->status = 0; + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) + PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", ret); +} + +/* * add data to the current frame * * This function is called by the subdrivers at interrupt level. @@ -379,10 +426,11 @@ static void destroy_urbs(struct gspca_dev *gspca_dev) } /* - * search an input isochronous endpoint in an alternate setting + * search an input transfer endpoint in an alternate setting */ -static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt, - __u8 epaddr) +static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, + __u8 epaddr, + __u8 xfer) { struct usb_host_endpoint *ep; int i, attr; @@ -393,7 +441,7 @@ static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt, if (ep->desc.bEndpointAddress == epaddr) { attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - if (attr == USB_ENDPOINT_XFER_ISOC) + if (attr == xfer) return ep; break; } @@ -402,14 +450,14 @@ static struct usb_host_endpoint *alt_isoc(struct usb_host_interface *alt, } /* - * search an input isochronous endpoint + * search an input (isoc or bulk) endpoint * * The endpoint is defined by the subdriver. * Use only the first isoc (some Zoran - 0x0572:0x0001 - have two such ep). * This routine may be called many times when the bandwidth is too small * (the bandwidth is checked on urb submit). */ -static struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev) +static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev) { struct usb_interface *intf; struct usb_host_endpoint *ep; @@ -419,15 +467,19 @@ static struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev) ep = NULL; i = gspca_dev->alt; /* previous alt setting */ while (--i > 0) { /* alt 0 is unusable */ - ep = alt_isoc(&intf->altsetting[i], gspca_dev->cam.epaddr); + ep = alt_xfer(&intf->altsetting[i], + gspca_dev->cam.epaddr, + gspca_dev->bulk + ? USB_ENDPOINT_XFER_BULK + : USB_ENDPOINT_XFER_ISOC); if (ep) break; } if (ep == NULL) { - err("no ISOC endpoint found"); + err("no transfer endpoint found"); return NULL; } - PDEBUG(D_STREAM, "use ISOC alt %d ep 0x%02x", + PDEBUG(D_STREAM, "use alt %d ep 0x%02x", i, ep->desc.bEndpointAddress); ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i); if (ret < 0) { @@ -439,7 +491,7 @@ static struct usb_host_endpoint *get_isoc_ep(struct gspca_dev *gspca_dev) } /* - * create the isochronous URBs + * create the URBs for image transfer */ static int create_urbs(struct gspca_dev *gspca_dev, struct usb_host_endpoint *ep) @@ -452,18 +504,28 @@ static int create_urbs(struct gspca_dev *gspca_dev, /* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3)); - npkt = ISO_MAX_SIZE / psize; - if (npkt > ISO_MAX_PKT) - npkt = ISO_MAX_PKT; - bsize = psize * npkt; - PDEBUG(D_STREAM, - "isoc %d pkts size %d (bsize:%d)", npkt, psize, bsize); + if (!gspca_dev->bulk) { + npkt = ISO_MAX_SIZE / psize; + if (npkt > ISO_MAX_PKT) + npkt = ISO_MAX_PKT; + bsize = psize * npkt; + PDEBUG(D_STREAM, + "isoc %d pkts size %d = bsize:%d", + npkt, psize, bsize); + } else { + npkt = 0; + bsize = psize; + PDEBUG(D_STREAM, "bulk bsize:%d", bsize); + } + nurbs = DEF_NURBS; gspca_dev->nurbs = nurbs; for (n = 0; n < nurbs; n++) { urb = usb_alloc_urb(npkt, GFP_KERNEL); if (!urb) { err("usb_alloc_urb failed"); + for (i = 0; i < n; i++) + usb_free_urb(gspca_dev->urb[i]); return -ENOMEM; } urb->transfer_buffer = usb_buffer_alloc(gspca_dev->dev, @@ -480,17 +542,23 @@ static int create_urbs(struct gspca_dev *gspca_dev, gspca_dev->urb[n] = urb; urb->dev = gspca_dev->dev; urb->context = gspca_dev; - urb->pipe = usb_rcvisocpipe(gspca_dev->dev, - ep->desc.bEndpointAddress); - urb->transfer_flags = URB_ISO_ASAP - | URB_NO_TRANSFER_DMA_MAP; - urb->interval = ep->desc.bInterval; - urb->complete = isoc_irq; - urb->number_of_packets = npkt; urb->transfer_buffer_length = bsize; - for (i = 0; i < npkt; i++) { - urb->iso_frame_desc[i].length = psize; - urb->iso_frame_desc[i].offset = psize * i; + if (npkt != 0) { /* ISOC */ + urb->pipe = usb_rcvisocpipe(gspca_dev->dev, + ep->desc.bEndpointAddress); + urb->transfer_flags = URB_ISO_ASAP + | URB_NO_TRANSFER_DMA_MAP; + urb->interval = ep->desc.bInterval; + urb->complete = isoc_irq; + urb->number_of_packets = npkt; + for (i = 0; i < npkt; i++) { + urb->iso_frame_desc[i].length = psize; + urb->iso_frame_desc[i].offset = psize * i; + } + } else { /* bulk */ + urb->pipe = usb_rcvbulkpipe(gspca_dev->dev, + ep->desc.bEndpointAddress), + urb->complete = bulk_irq; } } return 0; @@ -512,7 +580,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) gspca_dev->alt = gspca_dev->nbalt; for (;;) { PDEBUG(D_STREAM, "init transfer alt %d", gspca_dev->alt); - ep = get_isoc_ep(gspca_dev); + ep = get_ep(gspca_dev); if (ep == NULL) { ret = -EIO; goto out; @@ -563,10 +631,12 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev) gspca_dev->streaming = 0; atomic_set(&gspca_dev->nevent, 0); if (gspca_dev->present) { - gspca_dev->sd_desc->stopN(gspca_dev); + if (gspca_dev->sd_desc->stopN) + gspca_dev->sd_desc->stopN(gspca_dev); destroy_urbs(gspca_dev); gspca_set_alt0(gspca_dev); - gspca_dev->sd_desc->stop0(gspca_dev); + if (gspca_dev->sd_desc->stop0) + gspca_dev->sd_desc->stop0(gspca_dev); PDEBUG(D_STREAM, "stream off OK"); } } @@ -775,19 +845,7 @@ static int dev_open(struct inode *inode, struct file *file) goto out; } - /* if not done yet, initialize the sensor */ - if (gspca_dev->users == 0) { - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { - ret = -ERESTARTSYS; - goto out; - } - ret = gspca_dev->sd_desc->open(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - if (ret != 0) { - PDEBUG(D_ERR|D_CONF, "init device failed %d", ret); - goto out; - } - } else if (gspca_dev->users > 4) { /* (arbitrary value) */ + if (gspca_dev->users > 4) { /* (arbitrary value) */ ret = -EBUSY; goto out; } @@ -800,6 +858,7 @@ static int dev_open(struct inode *inode, struct file *file) else gspca_dev->vdev.debug &= ~3; #endif + ret = 0; out: mutex_unlock(&gspca_dev->queue_lock); if (ret != 0) @@ -820,11 +879,11 @@ static int dev_close(struct inode *inode, struct file *file) /* if the file did the capture, free the streaming resources */ if (gspca_dev->capt_file == file) { - mutex_lock(&gspca_dev->usb_lock); - if (gspca_dev->streaming) + if (gspca_dev->streaming) { + mutex_lock(&gspca_dev->usb_lock); gspca_stream_off(gspca_dev); - gspca_dev->sd_desc->close(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); + mutex_unlock(&gspca_dev->usb_lock); + } frame_free(gspca_dev); gspca_dev->capt_file = NULL; gspca_dev->memory = GSPCA_MEMORY_NO; @@ -858,42 +917,47 @@ static int vidioc_querycap(struct file *file, void *priv, 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; } -/* the use of V4L2_CTRL_FLAG_NEXT_CTRL asks for the controls to be sorted */ static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *q_ctrl) { struct gspca_dev *gspca_dev = priv; - int i; + int i, ix; u32 id; + ix = -1; id = q_ctrl->id; if (id & V4L2_CTRL_FLAG_NEXT_CTRL) { id &= V4L2_CTRL_ID_MASK; id++; for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { - if (id >= gspca_dev->sd_desc->ctrls[i].qctrl.id) { - memcpy(q_ctrl, - &gspca_dev->sd_desc->ctrls[i].qctrl, - sizeof *q_ctrl); - return 0; + if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id) + continue; + if (ix < 0) { + ix = i; + continue; } + if (gspca_dev->sd_desc->ctrls[i].qctrl.id + > gspca_dev->sd_desc->ctrls[ix].qctrl.id) + continue; + ix = i; } - return -EINVAL; } for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { if (id == gspca_dev->sd_desc->ctrls[i].qctrl.id) { - memcpy(q_ctrl, - &gspca_dev->sd_desc->ctrls[i].qctrl, - sizeof *q_ctrl); - return 0; + ix = i; + break; } } - return -EINVAL; + if (ix < 0) + return -EINVAL; + memcpy(q_ctrl, &gspca_dev->sd_desc->ctrls[ix].qctrl, + sizeof *q_ctrl); + if (gspca_dev->ctrl_dis & (1 << ix)) + q_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED; + return 0; } static int vidioc_s_ctrl(struct file *file, void *priv, @@ -908,6 +972,8 @@ static int vidioc_s_ctrl(struct file *file, void *priv, i++, ctrls++) { if (ctrl->id != ctrls->qctrl.id) continue; + if (gspca_dev->ctrl_dis & (1 << i)) + return -EINVAL; if (ctrl->value < ctrls->qctrl.minimum || ctrl->value > ctrls->qctrl.maximum) return -ERANGE; @@ -934,6 +1000,8 @@ static int vidioc_g_ctrl(struct file *file, void *priv, i++, ctrls++) { if (ctrl->id != ctrls->qctrl.id) continue; + if (gspca_dev->ctrl_dis & (1 << i)) + return -EINVAL; if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; ret = ctrls->get(gspca_dev, &ctrl->value); @@ -1408,7 +1476,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, i = ret; /* frame index */ frame = &gspca_dev->frame[i]; if (gspca_dev->memory == V4L2_MEMORY_USERPTR) { - if (copy_to_user((__u8 *) frame->v4l2_buf.m.userptr, + if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr, frame->data, frame->v4l2_buf.bytesused)) { PDEBUG(D_ERR|D_STREAM, @@ -1736,6 +1804,12 @@ int gspca_dev_probe(struct usb_interface *intf, err("couldn't kzalloc gspca struct"); return -EIO; } + gspca_dev->usb_buf = kmalloc(USB_BUF_SZ, GFP_KERNEL); + if (!gspca_dev->usb_buf) { + err("out of memory"); + ret = -EIO; + goto out; + } gspca_dev->dev = dev; gspca_dev->iface = interface->bInterfaceNumber; gspca_dev->nbalt = intf->num_altsetting; @@ -1743,10 +1817,13 @@ int gspca_dev_probe(struct usb_interface *intf, /* gspca_dev->users = 0; (done by kzalloc) */ gspca_dev->nbufread = 2; - /* configure the subdriver */ + /* configure the subdriver and initialize the USB device */ ret = gspca_dev->sd_desc->config(gspca_dev, id); if (ret < 0) goto out; + ret = gspca_dev->sd_desc->init(gspca_dev); + if (ret < 0) + goto out; ret = gspca_set_alt0(gspca_dev); if (ret < 0) goto out; @@ -1776,6 +1853,7 @@ int gspca_dev_probe(struct usb_interface *intf, PDEBUG(D_PROBE, "probe ok"); return 0; out: + kfree(gspca_dev->usb_buf); kfree(gspca_dev); return ret; } @@ -1808,6 +1886,7 @@ void gspca_disconnect(struct usb_interface *intf) /* We don't want people trying to open up the device */ video_unregister_device(&gspca_dev->vdev); /* Free the memory */ + kfree(gspca_dev->usb_buf); kfree(gspca_dev); PDEBUG(D_PROBE, "disconnect complete"); } @@ -1821,10 +1900,12 @@ int gspca_suspend(struct usb_interface *intf, pm_message_t message) if (!gspca_dev->streaming) return 0; gspca_dev->frozen = 1; /* avoid urb error messages */ - gspca_dev->sd_desc->stopN(gspca_dev); + if (gspca_dev->sd_desc->stopN) + gspca_dev->sd_desc->stopN(gspca_dev); destroy_urbs(gspca_dev); gspca_set_alt0(gspca_dev); - gspca_dev->sd_desc->stop0(gspca_dev); + if (gspca_dev->sd_desc->stop0) + gspca_dev->sd_desc->stop0(gspca_dev); return 0; } EXPORT_SYMBOL(gspca_suspend); @@ -1834,9 +1915,10 @@ 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); + gspca_dev->sd_desc->init(gspca_dev); + if (gspca_dev->streaming) + return gspca_init_transfer(gspca_dev); + return 0; } EXPORT_SYMBOL(gspca_resume); #endif diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h index 1920c99d6..78a35a88c 100644 --- a/linux/drivers/media/video/gspca/gspca.h +++ b/linux/drivers/media/video/gspca/gspca.h @@ -49,8 +49,8 @@ extern int gspca_debug; } while (0) #define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */ -/* ISOC transfers */ -#define MAX_NURBS 16 /* max number of URBs */ +/* image transfers */ +#define MAX_NURBS 4 /* max number of URBs */ #define ISO_MAX_PKT 32 /* max number of packets in an ISOC transfer */ #define ISO_MAX_SIZE 0x8000 /* max size of one URB buffer (32 Kb) */ @@ -90,15 +90,14 @@ struct sd_desc { /* controls */ const struct ctrl *ctrls; int nctrls; -/* operations */ +/* mandatory operations */ cam_cf_op config; /* called on probe */ - cam_op open; /* called on open */ + cam_op init; /* called on probe and resume */ cam_v_op start; /* called on stream on */ - cam_v_op stopN; /* called on stream off - main alt */ - cam_v_op stop0; /* called on stream off - alt 0 */ - cam_v_op close; /* called on close */ cam_pkt_op pkt_scan; /* optional operations */ + cam_v_op stopN; /* called on stream off - main alt */ + cam_v_op stop0; /* called on stream off - alt 0 */ cam_v_op dq_callback; /* called when a frame has been dequeued */ cam_jpg_op get_jcomp; cam_jpg_op set_jcomp; @@ -118,9 +117,6 @@ 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; @@ -129,8 +125,10 @@ struct gspca_dev { struct cam cam; /* device information */ const struct sd_desc *sd_desc; /* subdriver description */ + unsigned ctrl_dis; /* disabled controls (bit map) */ - __u8 usb_buf[8]; /* buffer for USB exchanges */ +#define USB_BUF_SZ 64 + __u8 *usb_buf; /* buffer for USB exchanges */ struct urb *urb[MAX_NURBS]; __u8 *frbuf; /* buffer for nframes */ @@ -145,6 +143,7 @@ struct gspca_dev { __u8 iface; /* USB interface number */ __u8 alt; /* USB alternate setting */ + __u8 bulk; /* image transfer by isoc (0) or bulk (1) */ __u8 curr_mode; /* current camera mode */ __u32 pixfmt; /* current mode parameters */ __u16 width; @@ -166,7 +165,6 @@ struct gspca_dev { 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, diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c index d7e209578..4d5db47ba 100644 --- a/linux/drivers/media/video/gspca/mars.c +++ b/linux/drivers/media/video/gspca/mars.c @@ -100,22 +100,6 @@ static int reg_w(struct gspca_dev *gspca_dev, return rc; } -static int reg_w_buf(struct gspca_dev *gspca_dev, - __u16 index, __u8 *buf, int len) -{ - int rc; - - rc = usb_control_msg(gspca_dev->dev, - usb_sndbulkpipe(gspca_dev->dev, 4), - 0x12, - 0xc8, /* ?? */ - 0, /* value */ - index, buf, len, 500); - if (rc < 0) - PDEBUG(D_ERR, "reg write [%02x] error %d", index, rc); - return rc; -} - static void bulk_w(struct gspca_dev *gspca_dev, __u16 *pch, __u16 Address) @@ -144,8 +128,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { return 0; } @@ -175,7 +159,6 @@ static void sd_start(struct gspca_dev *gspca_dev) /* Initialize the MR97113 chip register */ - data = kmalloc(16, GFP_KERNEL); data[0] = 0x00; /* address */ data[1] = 0x0c | 0x01; /* reg 0 */ data[2] = 0x01; /* reg 1 */ @@ -195,12 +178,10 @@ static void sd_start(struct gspca_dev *gspca_dev) data[10] = 0x5d; /* reg 9, I2C device address * [for PAS5101 (0x40)] [for MI (0x5d)] */ - err_code = reg_w_buf(gspca_dev, data[0], data, 11); - kfree(data); + err_code = reg_w(gspca_dev, data[0], 11); if (err_code < 0) return; - data = gspca_dev->usb_buf; data[0] = 0x23; /* address */ data[1] = 0x09; /* reg 35, append frame header */ @@ -358,14 +339,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) PDEBUG(D_ERR, "Camera Stop failed"); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -411,11 +384,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; diff --git a/linux/drivers/media/video/gspca/ov519.c b/linux/drivers/media/video/gspca/ov519.c index e1c665b4d..bb2842114 100644 --- a/linux/drivers/media/video/gspca/ov519.c +++ b/linux/drivers/media/video/gspca/ov519.c @@ -63,11 +63,10 @@ struct sd { #define SEN_OV6630 2 #define SEN_OV7610 3 #define SEN_OV7620 4 -#define SEN_OV7630 5 -#define SEN_OV7640 6 -#define SEN_OV7670 7 -#define SEN_OV76BE 8 -#define SEN_OV8610 9 +#define SEN_OV7640 5 +#define SEN_OV7670 6 +#define SEN_OV76BE 7 +#define SEN_OV8610 8 }; @@ -127,6 +126,7 @@ static struct ctrl sd_ctrls[] = { .get = sd_getcolors, }, /* next controls work with ov7670 only */ +#define HFLIP_IDX 3 { { .id = V4L2_CID_HFLIP, @@ -141,6 +141,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_sethflip, .get = sd_gethflip, }, +#define VFLIP_IDX 4 { { .id = V4L2_CID_VFLIP, @@ -293,6 +294,541 @@ 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 ov_regvals { + __u8 reg; + __u8 val; +}; +struct ov_i2c_regvals { + __u8 reg; + __u8 val; +}; + +static const struct ov_i2c_regvals norm_6x20[] = { + { 0x12, 0x80 }, /* reset */ + { 0x11, 0x01 }, + { 0x03, 0x60 }, + { 0x05, 0x7f }, /* For when autoadjust is off */ + { 0x07, 0xa8 }, + /* The ratio of 0x0c and 0x0d controls the white point */ + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, + { 0x0f, 0x15 }, /* COMS */ + { 0x10, 0x75 }, /* AEC Exposure time */ + { 0x12, 0x24 }, /* Enable AGC */ + { 0x14, 0x04 }, + /* 0x16: 0x06 helps frame stability with moving objects */ + { 0x16, 0x06 }, +/* { 0x20, 0x30 }, * Aperture correction enable */ + { 0x26, 0xb2 }, /* BLC enable */ + /* 0x28: 0x05 Selects RGB format if RGB on */ + { 0x28, 0x05 }, + { 0x2a, 0x04 }, /* Disable framerate adjust */ +/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */ + { 0x2d, 0x99 }, + { 0x33, 0xa0 }, /* Color Processing Parameter */ + { 0x34, 0xd2 }, /* Max A/D range */ + { 0x38, 0x8b }, + { 0x39, 0x40 }, + + { 0x3c, 0x39 }, /* Enable AEC mode changing */ + { 0x3c, 0x3c }, /* Change AEC mode */ + { 0x3c, 0x24 }, /* Disable AEC mode changing */ + + { 0x3d, 0x80 }, + /* These next two registers (0x4a, 0x4b) are undocumented. + * They control the color balance */ + { 0x4a, 0x80 }, + { 0x4b, 0x80 }, + { 0x4d, 0xd2 }, /* This reduces noise a bit */ + { 0x4e, 0xc1 }, + { 0x4f, 0x04 }, +/* Do 50-53 have any effect? */ +/* Toggle 0x12[2] off and on here? */ +}; + +static const struct ov_i2c_regvals norm_6x30[] = { + { 0x12, 0x80 }, /* Reset */ + { 0x00, 0x1f }, /* Gain */ + { 0x01, 0x99 }, /* Blue gain */ + { 0x02, 0x7c }, /* Red gain */ + { 0x03, 0xc0 }, /* Saturation */ + { 0x05, 0x0a }, /* Contrast */ + { 0x06, 0x95 }, /* Brightness */ + { 0x07, 0x2d }, /* Sharpness */ + { 0x0c, 0x20 }, + { 0x0d, 0x20 }, + { 0x0e, 0x20 }, + { 0x0f, 0x05 }, + { 0x10, 0x9a }, + { 0x11, 0x00 }, /* Pixel clock = fastest */ + { 0x12, 0x24 }, /* Enable AGC and AWB */ + { 0x13, 0x21 }, + { 0x14, 0x80 }, + { 0x15, 0x01 }, + { 0x16, 0x03 }, + { 0x17, 0x38 }, + { 0x18, 0xea }, + { 0x19, 0x04 }, + { 0x1a, 0x93 }, + { 0x1b, 0x00 }, + { 0x1e, 0xc4 }, + { 0x1f, 0x04 }, + { 0x20, 0x20 }, + { 0x21, 0x10 }, + { 0x22, 0x88 }, + { 0x23, 0xc0 }, /* Crystal circuit power level */ + { 0x25, 0x9a }, /* Increase AEC black ratio */ + { 0x26, 0xb2 }, /* BLC enable */ + { 0x27, 0xa2 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x84 }, /* 60 Hz power */ + { 0x2b, 0xa8 }, /* 60 Hz power */ + { 0x2c, 0xa0 }, + { 0x2d, 0x95 }, /* Enable auto-brightness */ + { 0x2e, 0x88 }, + { 0x33, 0x26 }, + { 0x34, 0x03 }, + { 0x36, 0x8f }, + { 0x37, 0x80 }, + { 0x38, 0x83 }, + { 0x39, 0x80 }, + { 0x3a, 0x0f }, + { 0x3b, 0x3c }, + { 0x3c, 0x1a }, + { 0x3d, 0x80 }, + { 0x3e, 0x80 }, + { 0x3f, 0x0e }, + { 0x40, 0x00 }, /* White bal */ + { 0x41, 0x00 }, /* White bal */ + { 0x42, 0x80 }, + { 0x43, 0x3f }, /* White bal */ + { 0x44, 0x80 }, + { 0x45, 0x20 }, + { 0x46, 0x20 }, + { 0x47, 0x80 }, + { 0x48, 0x7f }, + { 0x49, 0x00 }, + { 0x4a, 0x00 }, + { 0x4b, 0x80 }, + { 0x4c, 0xd0 }, + { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ + { 0x4e, 0x40 }, + { 0x4f, 0x07 }, /* UV avg., col. killer: max */ + { 0x50, 0xff }, + { 0x54, 0x23 }, /* Max AGC gain: 18dB */ + { 0x55, 0xff }, + { 0x56, 0x12 }, + { 0x57, 0x81 }, + { 0x58, 0x75 }, + { 0x59, 0x01 }, /* AGC dark current comp.: +1 */ + { 0x5a, 0x2c }, + { 0x5b, 0x0f }, /* AWB chrominance levels */ + { 0x5c, 0x10 }, + { 0x3d, 0x80 }, + { 0x27, 0xa6 }, + { 0x12, 0x20 }, /* Toggle AWB */ + { 0x12, 0x24 }, +}; + +/* Lawrence Glaister <lg@jfm.bc.ca> reports: + * + * Register 0x0f in the 7610 has the following effects: + * + * 0x85 (AEC method 1): Best overall, good contrast range + * 0x45 (AEC method 2): Very overexposed + * 0xa5 (spec sheet default): Ok, but the black level is + * shifted resulting in loss of contrast + * 0x05 (old driver setting): very overexposed, too much + * contrast + */ +static const struct ov_i2c_regvals norm_7610[] = { + { 0x10, 0xff }, + { 0x16, 0x06 }, + { 0x28, 0x24 }, + { 0x2b, 0xac }, + { 0x12, 0x00 }, + { 0x38, 0x81 }, + { 0x28, 0x24 }, /* 0c */ + { 0x0f, 0x85 }, /* lg's setting */ + { 0x15, 0x01 }, + { 0x20, 0x1c }, + { 0x23, 0x2a }, + { 0x24, 0x10 }, + { 0x25, 0x8a }, + { 0x26, 0xa2 }, + { 0x27, 0xc2 }, + { 0x2a, 0x04 }, + { 0x2c, 0xfe }, + { 0x2d, 0x93 }, + { 0x30, 0x71 }, + { 0x31, 0x60 }, + { 0x32, 0x26 }, + { 0x33, 0x20 }, + { 0x34, 0x48 }, + { 0x12, 0x24 }, + { 0x11, 0x01 }, + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, +}; + +static const struct ov_i2c_regvals norm_7620[] = { + { 0x00, 0x00 }, /* gain */ + { 0x01, 0x80 }, /* blue gain */ + { 0x02, 0x80 }, /* red gain */ + { 0x03, 0xc0 }, /* OV7670_REG_VREF */ + { 0x06, 0x60 }, + { 0x07, 0x00 }, + { 0x0c, 0x24 }, + { 0x0c, 0x24 }, + { 0x0d, 0x24 }, + { 0x11, 0x01 }, + { 0x12, 0x24 }, + { 0x13, 0x01 }, + { 0x14, 0x84 }, + { 0x15, 0x01 }, + { 0x16, 0x03 }, + { 0x17, 0x2f }, + { 0x18, 0xcf }, + { 0x19, 0x06 }, + { 0x1a, 0xf5 }, + { 0x1b, 0x00 }, + { 0x20, 0x18 }, + { 0x21, 0x80 }, + { 0x22, 0x80 }, + { 0x23, 0x00 }, + { 0x26, 0xa2 }, + { 0x27, 0xea }, + { 0x28, 0x20 }, + { 0x29, 0x00 }, + { 0x2a, 0x10 }, + { 0x2b, 0x00 }, + { 0x2c, 0x88 }, + { 0x2d, 0x91 }, + { 0x2e, 0x80 }, + { 0x2f, 0x44 }, + { 0x60, 0x27 }, + { 0x61, 0x02 }, + { 0x62, 0x5f }, + { 0x63, 0xd5 }, + { 0x64, 0x57 }, + { 0x65, 0x83 }, + { 0x66, 0x55 }, + { 0x67, 0x92 }, + { 0x68, 0xcf }, + { 0x69, 0x76 }, + { 0x6a, 0x22 }, + { 0x6b, 0x00 }, + { 0x6c, 0x02 }, + { 0x6d, 0x44 }, + { 0x6e, 0x80 }, + { 0x6f, 0x1d }, + { 0x70, 0x8b }, + { 0x71, 0x00 }, + { 0x72, 0x14 }, + { 0x73, 0x54 }, + { 0x74, 0x00 }, + { 0x75, 0x8e }, + { 0x76, 0x00 }, + { 0x77, 0xff }, + { 0x78, 0x80 }, + { 0x79, 0x80 }, + { 0x7a, 0x80 }, + { 0x7b, 0xe2 }, + { 0x7c, 0x00 }, +}; + +/* 7640 and 7648. The defaults should be OK for most registers. */ +static const struct ov_i2c_regvals norm_7640[] = { + { 0x12, 0x80 }, + { 0x12, 0x14 }, +}; + +/* 7670. Defaults taken from OmniVision provided data, +* as provided by Jonathan Corbet of OLPC */ +static const struct ov_i2c_regvals norm_7670[] = { + { OV7670_REG_COM7, OV7670_COM7_RESET }, + { OV7670_REG_TSLB, 0x04 }, /* OV */ + { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ + { 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... + */ + { OV7670_REG_HSTART, 0x13 }, + { OV7670_REG_HSTOP, 0x01 }, + { OV7670_REG_HREF, 0xb6 }, + { OV7670_REG_VSTART, 0x02 }, + { OV7670_REG_VSTOP, 0x7a }, + { OV7670_REG_VREF, 0x0a }, + + { OV7670_REG_COM3, 0 }, + { OV7670_REG_COM14, 0 }, +/* Mystery scaling numbers */ + { 0x70, 0x3a }, + { 0x71, 0x35 }, + { 0x72, 0x11 }, + { 0x73, 0xf0 }, + { 0xa2, 0x02 }, +/* { OV7670_REG_COM10, 0x0 }, */ + +/* Gamma curve values */ + { 0x7a, 0x20 }, + { 0x7b, 0x10 }, + { 0x7c, 0x1e }, + { 0x7d, 0x35 }, + { 0x7e, 0x5a }, + { 0x7f, 0x69 }, + { 0x80, 0x76 }, + { 0x81, 0x80 }, + { 0x82, 0x88 }, + { 0x83, 0x8f }, + { 0x84, 0x96 }, + { 0x85, 0xa3 }, + { 0x86, 0xaf }, + { 0x87, 0xc4 }, + { 0x88, 0xd7 }, + { 0x89, 0xe8 }, + +/* AGC and AEC parameters. Note we start by disabling those features, + then turn them only after tweaking the values. */ + { OV7670_REG_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT }, + { OV7670_REG_GAIN, 0 }, + { OV7670_REG_AECH, 0 }, + { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ + { 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 }, + { 0xa1, 0x03 }, /* magic */ + { OV7670_REG_HAECC3, 0xd8 }, + { OV7670_REG_HAECC4, 0xd8 }, + { OV7670_REG_HAECC5, 0xf0 }, + { OV7670_REG_HAECC6, 0x90 }, + { OV7670_REG_HAECC7, 0x94 }, + { OV7670_REG_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT + | OV7670_COM8_AGC + | OV7670_COM8_AEC }, + +/* Almost all of these are magic "reserved" values. */ + { OV7670_REG_COM5, 0x61 }, + { OV7670_REG_COM6, 0x4b }, + { 0x16, 0x02 }, + { OV7670_REG_MVFP, 0x07 }, + { 0x21, 0x02 }, + { 0x22, 0x91 }, + { 0x29, 0x07 }, + { 0x33, 0x0b }, + { 0x35, 0x0b }, + { 0x37, 0x1d }, + { 0x38, 0x71 }, + { 0x39, 0x2a }, + { OV7670_REG_COM12, 0x78 }, + { 0x4d, 0x40 }, + { 0x4e, 0x20 }, + { OV7670_REG_GFIX, 0 }, + { 0x6b, 0x4a }, + { 0x74, 0x10 }, + { 0x8d, 0x4f }, + { 0x8e, 0 }, + { 0x8f, 0 }, + { 0x90, 0 }, + { 0x91, 0 }, + { 0x96, 0 }, + { 0x9a, 0 }, + { 0xb0, 0x84 }, + { 0xb1, 0x0c }, + { 0xb2, 0x0e }, + { 0xb3, 0x82 }, + { 0xb8, 0x0a }, + +/* More reserved magic, some of which tweaks white balance */ + { 0x43, 0x0a }, + { 0x44, 0xf0 }, + { 0x45, 0x34 }, + { 0x46, 0x58 }, + { 0x47, 0x28 }, + { 0x48, 0x3a }, + { 0x59, 0x88 }, + { 0x5a, 0x88 }, + { 0x5b, 0x44 }, + { 0x5c, 0x67 }, + { 0x5d, 0x49 }, + { 0x5e, 0x0e }, + { 0x6c, 0x0a }, + { 0x6d, 0x55 }, + { 0x6e, 0x11 }, + { 0x6f, 0x9f }, + /* "9e for advance AWB" */ + { 0x6a, 0x40 }, + { OV7670_REG_BLUE, 0x40 }, + { OV7670_REG_RED, 0x60 }, + { OV7670_REG_COM8, OV7670_COM8_FASTAEC + | OV7670_COM8_AECSTEP + | OV7670_COM8_BFILT + | OV7670_COM8_AGC + | OV7670_COM8_AEC + | OV7670_COM8_AWB }, + +/* Matrix coefficients */ + { 0x4f, 0x80 }, + { 0x50, 0x80 }, + { 0x51, 0 }, + { 0x52, 0x22 }, + { 0x53, 0x5e }, + { 0x54, 0x80 }, + { 0x58, 0x9e }, + + { OV7670_REG_COM16, OV7670_COM16_AWBGAIN }, + { OV7670_REG_EDGE, 0 }, + { 0x75, 0x05 }, + { 0x76, 0xe1 }, + { 0x4c, 0 }, + { 0x77, 0x01 }, + { OV7670_REG_COM13, OV7670_COM13_GAMMA + | OV7670_COM13_UVSAT + | 2}, /* was 3 */ + { 0x4b, 0x09 }, + { 0xc9, 0x60 }, + { OV7670_REG_COM16, 0x38 }, + { 0x56, 0x40 }, + + { 0x34, 0x11 }, + { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO }, + { 0xa4, 0x88 }, + { 0x96, 0 }, + { 0x97, 0x30 }, + { 0x98, 0x20 }, + { 0x99, 0x30 }, + { 0x9a, 0x84 }, + { 0x9b, 0x29 }, + { 0x9c, 0x03 }, + { 0x9d, 0x4c }, + { 0x9e, 0x3f }, + { 0x78, 0x04 }, + +/* Extra-weird stuff. Some sort of multiplexor register */ + { 0x79, 0x01 }, + { 0xc8, 0xf0 }, + { 0x79, 0x0f }, + { 0xc8, 0x00 }, + { 0x79, 0x10 }, + { 0xc8, 0x7e }, + { 0x79, 0x0a }, + { 0xc8, 0x80 }, + { 0x79, 0x0b }, + { 0xc8, 0x01 }, + { 0x79, 0x0c }, + { 0xc8, 0x0f }, + { 0x79, 0x0d }, + { 0xc8, 0x20 }, + { 0x79, 0x09 }, + { 0xc8, 0x80 }, + { 0x79, 0x02 }, + { 0xc8, 0xc0 }, + { 0x79, 0x03 }, + { 0xc8, 0x40 }, + { 0x79, 0x05 }, + { 0xc8, 0x30 }, + { 0x79, 0x26 }, +}; + +static const struct ov_i2c_regvals norm_8610[] = { + { 0x12, 0x80 }, + { 0x00, 0x00 }, + { 0x01, 0x80 }, + { 0x02, 0x80 }, + { 0x03, 0xc0 }, + { 0x04, 0x30 }, + { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */ + { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */ + { 0x0a, 0x86 }, + { 0x0b, 0xb0 }, + { 0x0c, 0x20 }, + { 0x0d, 0x20 }, + { 0x11, 0x01 }, + { 0x12, 0x25 }, + { 0x13, 0x01 }, + { 0x14, 0x04 }, + { 0x15, 0x01 }, /* Lin and Win think different about UV order */ + { 0x16, 0x03 }, + { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */ + { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */ + { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */ + { 0x1a, 0xf5 }, + { 0x1b, 0x00 }, + { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */ + { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */ + { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */ + { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */ + { 0x26, 0xa2 }, + { 0x27, 0xea }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x80 }, + { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */ + { 0x2c, 0xac }, + { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */ + { 0x2e, 0x80 }, + { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */ + { 0x4c, 0x00 }, + { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */ + { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */ + { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */ + { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */ + { 0x63, 0xff }, + { 0x64, 0x53 }, /* new windrv 090403 says 0x57, + * maybe thats wrong */ + { 0x65, 0x00 }, + { 0x66, 0x55 }, + { 0x67, 0xb0 }, + { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */ + { 0x69, 0x02 }, + { 0x6a, 0x22 }, + { 0x6b, 0x00 }, + { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but + * deleting bit7 colors the first images red */ + { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */ + { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */ + { 0x6f, 0x01 }, + { 0x70, 0x8b }, + { 0x71, 0x00 }, + { 0x72, 0x14 }, + { 0x73, 0x54 }, + { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */ + { 0x75, 0x0e }, + { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */ + { 0x77, 0xff }, + { 0x78, 0x80 }, + { 0x79, 0x80 }, + { 0x7a, 0x80 }, + { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */ + { 0x7c, 0x00 }, + { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */ + { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */ + { 0x7f, 0xfb }, + { 0x80, 0x28 }, + { 0x81, 0x00 }, + { 0x82, 0x23 }, + { 0x83, 0x0b }, + { 0x84, 0x00 }, + { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */ + { 0x86, 0xc9 }, + { 0x87, 0x00 }, + { 0x88, 0x00 }, + { 0x89, 0x01 }, + { 0x12, 0x20 }, + { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */ +}; + static unsigned char ov7670_abs_to_sm(unsigned char v) { if (v > 127) @@ -537,18 +1073,10 @@ static int ov51x_set_slave_ids(struct sd *sd, rc = reg_w(sd, R51x_I2C_W_SID, slave); if (rc < 0) return rc; + sd->primary_i2c_slave = slave; return reg_w(sd, R51x_I2C_R_SID, slave + 1); } -struct ov_regvals { - __u8 reg; - __u8 val; -}; -struct ov_i2c_regvals { - __u8 reg; - __u8 val; -}; - static int write_regvals(struct sd *sd, const struct ov_regvals *regvals, int n) @@ -591,101 +1119,9 @@ static int write_i2c_regvals(struct sd *sd, static int ov8xx0_configure(struct sd *sd) { int rc; - static const struct ov_i2c_regvals norm_8610[] = { - { 0x12, 0x80 }, - { 0x00, 0x00 }, - { 0x01, 0x80 }, - { 0x02, 0x80 }, - { 0x03, 0xc0 }, - { 0x04, 0x30 }, - { 0x05, 0x30 }, /* was 0x10, new from windrv 090403 */ - { 0x06, 0x70 }, /* was 0x80, new from windrv 090403 */ - { 0x0a, 0x86 }, - { 0x0b, 0xb0 }, - { 0x0c, 0x20 }, - { 0x0d, 0x20 }, - { 0x11, 0x01 }, - { 0x12, 0x25 }, - { 0x13, 0x01 }, - { 0x14, 0x04 }, - { 0x15, 0x01 }, /* Lin and Win think different about UV order */ - { 0x16, 0x03 }, - { 0x17, 0x38 }, /* was 0x2f, new from windrv 090403 */ - { 0x18, 0xea }, /* was 0xcf, new from windrv 090403 */ - { 0x19, 0x02 }, /* was 0x06, new from windrv 090403 */ - { 0x1a, 0xf5 }, - { 0x1b, 0x00 }, - { 0x20, 0xd0 }, /* was 0x90, new from windrv 090403 */ - { 0x23, 0xc0 }, /* was 0x00, new from windrv 090403 */ - { 0x24, 0x30 }, /* was 0x1d, new from windrv 090403 */ - { 0x25, 0x50 }, /* was 0x57, new from windrv 090403 */ - { 0x26, 0xa2 }, - { 0x27, 0xea }, - { 0x28, 0x00 }, - { 0x29, 0x00 }, - { 0x2a, 0x80 }, - { 0x2b, 0xc8 }, /* was 0xcc, new from windrv 090403 */ - { 0x2c, 0xac }, - { 0x2d, 0x45 }, /* was 0xd5, new from windrv 090403 */ - { 0x2e, 0x80 }, - { 0x2f, 0x14 }, /* was 0x01, new from windrv 090403 */ - { 0x4c, 0x00 }, - { 0x4d, 0x30 }, /* was 0x10, new from windrv 090403 */ - { 0x60, 0x02 }, /* was 0x01, new from windrv 090403 */ - { 0x61, 0x00 }, /* was 0x09, new from windrv 090403 */ - { 0x62, 0x5f }, /* was 0xd7, new from windrv 090403 */ - { 0x63, 0xff }, - { 0x64, 0x53 }, /* new windrv 090403 says 0x57, - * maybe thats wrong */ - { 0x65, 0x00 }, - { 0x66, 0x55 }, - { 0x67, 0xb0 }, - { 0x68, 0xc0 }, /* was 0xaf, new from windrv 090403 */ - { 0x69, 0x02 }, - { 0x6a, 0x22 }, - { 0x6b, 0x00 }, - { 0x6c, 0x99 }, /* was 0x80, old windrv says 0x00, but - deleting bit7 colors the first images red */ - { 0x6d, 0x11 }, /* was 0x00, new from windrv 090403 */ - { 0x6e, 0x11 }, /* was 0x00, new from windrv 090403 */ - { 0x6f, 0x01 }, - { 0x70, 0x8b }, - { 0x71, 0x00 }, - { 0x72, 0x14 }, - { 0x73, 0x54 }, - { 0x74, 0x00 },/* 0x60? - was 0x00, new from windrv 090403 */ - { 0x75, 0x0e }, - { 0x76, 0x02 }, /* was 0x02, new from windrv 090403 */ - { 0x77, 0xff }, - { 0x78, 0x80 }, - { 0x79, 0x80 }, - { 0x7a, 0x80 }, - { 0x7b, 0x10 }, /* was 0x13, new from windrv 090403 */ - { 0x7c, 0x00 }, - { 0x7d, 0x08 }, /* was 0x09, new from windrv 090403 */ - { 0x7e, 0x08 }, /* was 0xc0, new from windrv 090403 */ - { 0x7f, 0xfb }, - { 0x80, 0x28 }, - { 0x81, 0x00 }, - { 0x82, 0x23 }, - { 0x83, 0x0b }, - { 0x84, 0x00 }, - { 0x85, 0x62 }, /* was 0x61, new from windrv 090403 */ - { 0x86, 0xc9 }, - { 0x87, 0x00 }, - { 0x88, 0x00 }, - { 0x89, 0x01 }, - { 0x12, 0x20 }, - { 0x12, 0x25 }, /* was 0x24, new from windrv 090403 */ - }; PDEBUG(D_PROBE, "starting ov8xx0 configuration"); - if (init_ov_sensor(sd) < 0) - PDEBUG(D_ERR|D_PROBE, "Failed to read sensor ID"); - else - PDEBUG(D_PROBE, "OV86x0 initialized"); - /* Detect sensor (sub)type */ rc = i2c_r(sd, OV7610_REG_COM_I); if (rc < 0) { @@ -698,9 +1134,6 @@ static int ov8xx0_configure(struct sd *sd) 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, ARRAY_SIZE(norm_8610))) - return -1; /* Set sensor-specific vars */ /* sd->sif = 0; already done */ @@ -714,252 +1147,6 @@ static int ov7xx0_configure(struct sd *sd) { int rc, high, low; - /* Lawrence Glaister <lg@jfm.bc.ca> reports: - * - * Register 0x0f in the 7610 has the following effects: - * - * 0x85 (AEC method 1): Best overall, good contrast range - * 0x45 (AEC method 2): Very overexposed - * 0xa5 (spec sheet default): Ok, but the black level is - * shifted resulting in loss of contrast - * 0x05 (old driver setting): very overexposed, too much - * contrast - */ - static const struct ov_i2c_regvals norm_7610[] = { - { 0x10, 0xff }, - { 0x16, 0x06 }, - { 0x28, 0x24 }, - { 0x2b, 0xac }, - { 0x12, 0x00 }, - { 0x38, 0x81 }, - { 0x28, 0x24 }, /* 0c */ - { 0x0f, 0x85 }, /* lg's setting */ - { 0x15, 0x01 }, - { 0x20, 0x1c }, - { 0x23, 0x2a }, - { 0x24, 0x10 }, - { 0x25, 0x8a }, - { 0x26, 0xa2 }, - { 0x27, 0xc2 }, - { 0x2a, 0x04 }, - { 0x2c, 0xfe }, - { 0x2d, 0x93 }, - { 0x30, 0x71 }, - { 0x31, 0x60 }, - { 0x32, 0x26 }, - { 0x33, 0x20 }, - { 0x34, 0x48 }, - { 0x12, 0x24 }, - { 0x11, 0x01 }, - { 0x0c, 0x24 }, - { 0x0d, 0x24 }, - }; - - static const struct ov_i2c_regvals norm_7620[] = { - { 0x00, 0x00 }, /* gain */ - { 0x01, 0x80 }, /* blue gain */ - { 0x02, 0x80 }, /* red gain */ - { 0x03, 0xc0 }, /* OV7670_REG_VREF */ - { 0x06, 0x60 }, - { 0x07, 0x00 }, - { 0x0c, 0x24 }, - { 0x0c, 0x24 }, - { 0x0d, 0x24 }, - { 0x11, 0x01 }, - { 0x12, 0x24 }, - { 0x13, 0x01 }, - { 0x14, 0x84 }, - { 0x15, 0x01 }, - { 0x16, 0x03 }, - { 0x17, 0x2f }, - { 0x18, 0xcf }, - { 0x19, 0x06 }, - { 0x1a, 0xf5 }, - { 0x1b, 0x00 }, - { 0x20, 0x18 }, - { 0x21, 0x80 }, - { 0x22, 0x80 }, - { 0x23, 0x00 }, - { 0x26, 0xa2 }, - { 0x27, 0xea }, - { 0x28, 0x20 }, - { 0x29, 0x00 }, - { 0x2a, 0x10 }, - { 0x2b, 0x00 }, - { 0x2c, 0x88 }, - { 0x2d, 0x91 }, - { 0x2e, 0x80 }, - { 0x2f, 0x44 }, - { 0x60, 0x27 }, - { 0x61, 0x02 }, - { 0x62, 0x5f }, - { 0x63, 0xd5 }, - { 0x64, 0x57 }, - { 0x65, 0x83 }, - { 0x66, 0x55 }, - { 0x67, 0x92 }, - { 0x68, 0xcf }, - { 0x69, 0x76 }, - { 0x6a, 0x22 }, - { 0x6b, 0x00 }, - { 0x6c, 0x02 }, - { 0x6d, 0x44 }, - { 0x6e, 0x80 }, - { 0x6f, 0x1d }, - { 0x70, 0x8b }, - { 0x71, 0x00 }, - { 0x72, 0x14 }, - { 0x73, 0x54 }, - { 0x74, 0x00 }, - { 0x75, 0x8e }, - { 0x76, 0x00 }, - { 0x77, 0xff }, - { 0x78, 0x80 }, - { 0x79, 0x80 }, - { 0x7a, 0x80 }, - { 0x7b, 0xe2 }, - { 0x7c, 0x00 }, - }; - - /* 7640 and 7648. The defaults should be OK for most registers. */ - static const struct ov_i2c_regvals norm_7640[] = { - { 0x12, 0x80 }, - { 0x12, 0x14 }, - }; - - /* 7670. Defaults taken from OmniVision provided data, - * as provided by Jonathan Corbet of OLPC */ - static const struct ov_i2c_regvals norm_7670[] = { - { OV7670_REG_COM7, OV7670_COM7_RESET }, - { OV7670_REG_TSLB, 0x04 }, /* OV */ - { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */ - { 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... - */ - { OV7670_REG_HSTART, 0x13 }, { OV7670_REG_HSTOP, 0x01 }, - { OV7670_REG_HREF, 0xb6 }, { OV7670_REG_VSTART, 0x02 }, - { OV7670_REG_VSTOP, 0x7a }, { OV7670_REG_VREF, 0x0a }, - - { OV7670_REG_COM3, 0 }, { OV7670_REG_COM14, 0 }, - /* Mystery scaling numbers */ - { 0x70, 0x3a }, { 0x71, 0x35 }, - { 0x72, 0x11 }, { 0x73, 0xf0 }, - { 0xa2, 0x02 }, -/* { OV7670_REG_COM10, 0x0 }, */ - - /* Gamma curve values */ - { 0x7a, 0x20 }, - { 0x7b, 0x10 }, - { 0x7c, 0x1e }, - { 0x7d, 0x35 }, - { 0x7e, 0x5a }, { 0x7f, 0x69 }, - { 0x80, 0x76 }, { 0x81, 0x80 }, - { 0x82, 0x88 }, { 0x83, 0x8f }, - { 0x84, 0x96 }, { 0x85, 0xa3 }, - { 0x86, 0xaf }, { 0x87, 0xc4 }, - { 0x88, 0xd7 }, { 0x89, 0xe8 }, - - /* AGC and AEC parameters. Note we start by disabling those features, - then turn them only after tweaking the values. */ - { OV7670_REG_COM8, OV7670_COM8_FASTAEC - | OV7670_COM8_AECSTEP - | OV7670_COM8_BFILT }, - { OV7670_REG_GAIN, 0 }, { OV7670_REG_AECH, 0 }, - { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */ - { 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 }, - { 0xa1, 0x03 }, /* magic */ - { OV7670_REG_HAECC3, 0xd8 }, { OV7670_REG_HAECC4, 0xd8 }, - { OV7670_REG_HAECC5, 0xf0 }, { OV7670_REG_HAECC6, 0x90 }, - { OV7670_REG_HAECC7, 0x94 }, - { OV7670_REG_COM8, OV7670_COM8_FASTAEC - | OV7670_COM8_AECSTEP - | OV7670_COM8_BFILT - | OV7670_COM8_AGC - | OV7670_COM8_AEC }, - - /* Almost all of these are magic "reserved" values. */ - { OV7670_REG_COM5, 0x61 }, { OV7670_REG_COM6, 0x4b }, - { 0x16, 0x02 }, - { OV7670_REG_MVFP, 0x07 }, - { 0x21, 0x02 }, { 0x22, 0x91 }, - { 0x29, 0x07 }, { 0x33, 0x0b }, - { 0x35, 0x0b }, { 0x37, 0x1d }, - { 0x38, 0x71 }, { 0x39, 0x2a }, - { OV7670_REG_COM12, 0x78 }, { 0x4d, 0x40 }, - { 0x4e, 0x20 }, { OV7670_REG_GFIX, 0 }, - { 0x6b, 0x4a }, { 0x74, 0x10 }, - { 0x8d, 0x4f }, { 0x8e, 0 }, - { 0x8f, 0 }, { 0x90, 0 }, - { 0x91, 0 }, { 0x96, 0 }, - { 0x9a, 0 }, { 0xb0, 0x84 }, - { 0xb1, 0x0c }, { 0xb2, 0x0e }, - { 0xb3, 0x82 }, { 0xb8, 0x0a }, - - /* More reserved magic, some of which tweaks white balance */ - { 0x43, 0x0a }, { 0x44, 0xf0 }, - { 0x45, 0x34 }, { 0x46, 0x58 }, - { 0x47, 0x28 }, { 0x48, 0x3a }, - { 0x59, 0x88 }, { 0x5a, 0x88 }, - { 0x5b, 0x44 }, { 0x5c, 0x67 }, - { 0x5d, 0x49 }, { 0x5e, 0x0e }, - { 0x6c, 0x0a }, { 0x6d, 0x55 }, - { 0x6e, 0x11 }, { 0x6f, 0x9f }, - /* "9e for advance AWB" */ - { 0x6a, 0x40 }, { OV7670_REG_BLUE, 0x40 }, - { OV7670_REG_RED, 0x60 }, - { OV7670_REG_COM8, OV7670_COM8_FASTAEC - | OV7670_COM8_AECSTEP - | OV7670_COM8_BFILT - | OV7670_COM8_AGC - | OV7670_COM8_AEC - | OV7670_COM8_AWB }, - - /* Matrix coefficients */ - { 0x4f, 0x80 }, { 0x50, 0x80 }, - { 0x51, 0 }, { 0x52, 0x22 }, - { 0x53, 0x5e }, { 0x54, 0x80 }, - { 0x58, 0x9e }, - - { OV7670_REG_COM16, OV7670_COM16_AWBGAIN }, - { OV7670_REG_EDGE, 0 }, - { 0x75, 0x05 }, { 0x76, 0xe1 }, - { 0x4c, 0 }, { 0x77, 0x01 }, - { OV7670_REG_COM13, OV7670_COM13_GAMMA - | OV7670_COM13_UVSAT - | 2}, /* was 3 */ - { 0x4b, 0x09 }, - { 0xc9, 0x60 }, { OV7670_REG_COM16, 0x38 }, - { 0x56, 0x40 }, - - { 0x34, 0x11 }, - { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO }, - { 0xa4, 0x88 }, { 0x96, 0 }, - { 0x97, 0x30 }, { 0x98, 0x20 }, - { 0x99, 0x30 }, { 0x9a, 0x84 }, - { 0x9b, 0x29 }, { 0x9c, 0x03 }, - { 0x9d, 0x4c }, { 0x9e, 0x3f }, - { 0x78, 0x04 }, - - /* Extra-weird stuff. Some sort of multiplexor register */ - { 0x79, 0x01 }, { 0xc8, 0xf0 }, - { 0x79, 0x0f }, { 0xc8, 0x00 }, - { 0x79, 0x10 }, { 0xc8, 0x7e }, - { 0x79, 0x0a }, { 0xc8, 0x80 }, - { 0x79, 0x0b }, { 0xc8, 0x01 }, - { 0x79, 0x0c }, { 0xc8, 0x0f }, - { 0x79, 0x0d }, { 0xc8, 0x20 }, - { 0x79, 0x09 }, { 0xc8, 0x80 }, - { 0x79, 0x02 }, { 0xc8, 0xc0 }, - { 0x79, 0x03 }, { 0xc8, 0x40 }, - { 0x79, 0x05 }, { 0xc8, 0x30 }, - { 0x79, 0x26 }, - }; PDEBUG(D_PROBE, "starting OV7xx0 configuration"); @@ -1011,8 +1198,9 @@ static int ov7xx0_configure(struct sd *sd) switch (low) { case 0x30: PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635"); - sd->sensor = SEN_OV7630; - break; + PDEBUG(D_ERR, + "7630 is not supported by this driver"); + return -1; case 0x40: PDEBUG(D_PROBE, "Sensor is an OV7645"); sd->sensor = SEN_OV7640; /* FIXME */ @@ -1038,32 +1226,6 @@ static int ov7xx0_configure(struct sd *sd) return -1; } - switch (sd->sensor) { - case SEN_OV7620: - PDEBUG(D_PROBE, "Writing 7620 registers"); - if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620))) - return -1; - break; - case SEN_OV7630: - PDEBUG(D_ERR, "7630 is not supported by this driver version"); - return -1; - case SEN_OV7640: - PDEBUG(D_PROBE, "Writing 7640 registers"); - if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640))) - return -1; - break; - case SEN_OV7670: - PDEBUG(D_PROBE, "Writing 7670 registers"); - if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670))) - return -1; - break; - default: - PDEBUG(D_PROBE, "Writing 7610 registers"); - if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610))) - return -1; - break; - } - /* Set sensor-specific vars */ /* sd->sif = 0; already done */ return 0; @@ -1073,141 +1235,7 @@ static int ov7xx0_configure(struct sd *sd) static int ov6xx0_configure(struct sd *sd) { int rc; - static const struct ov_i2c_regvals norm_6x20[] = { - { 0x12, 0x80 }, /* reset */ - { 0x11, 0x01 }, - { 0x03, 0x60 }, - { 0x05, 0x7f }, /* For when autoadjust is off */ - { 0x07, 0xa8 }, - /* The ratio of 0x0c and 0x0d controls the white point */ - { 0x0c, 0x24 }, - { 0x0d, 0x24 }, - { 0x0f, 0x15 }, /* COMS */ - { 0x10, 0x75 }, /* AEC Exposure time */ - { 0x12, 0x24 }, /* Enable AGC */ - { 0x14, 0x04 }, - /* 0x16: 0x06 helps frame stability with moving objects */ - { 0x16, 0x06 }, -/* { 0x20, 0x30 }, * Aperture correction enable */ - { 0x26, 0xb2 }, /* BLC enable */ - /* 0x28: 0x05 Selects RGB format if RGB on */ - { 0x28, 0x05 }, - { 0x2a, 0x04 }, /* Disable framerate adjust */ -/* { 0x2b, 0xac }, * Framerate; Set 2a[7] first */ - { 0x2d, 0x99 }, - { 0x33, 0xa0 }, /* Color Processing Parameter */ - { 0x34, 0xd2 }, /* Max A/D range */ - { 0x38, 0x8b }, - { 0x39, 0x40 }, - - { 0x3c, 0x39 }, /* Enable AEC mode changing */ - { 0x3c, 0x3c }, /* Change AEC mode */ - { 0x3c, 0x24 }, /* Disable AEC mode changing */ - - { 0x3d, 0x80 }, - /* These next two registers (0x4a, 0x4b) are undocumented. - * They control the color balance */ - { 0x4a, 0x80 }, - { 0x4b, 0x80 }, - { 0x4d, 0xd2 }, /* This reduces noise a bit */ - { 0x4e, 0xc1 }, - { 0x4f, 0x04 }, -/* Do 50-53 have any effect? */ -/* Toggle 0x12[2] off and on here? */ - }; - - static const struct ov_i2c_regvals norm_6x30[] = { - { 0x12, 0x80 }, /* Reset */ - { 0x00, 0x1f }, /* Gain */ - { 0x01, 0x99 }, /* Blue gain */ - { 0x02, 0x7c }, /* Red gain */ - { 0x03, 0xc0 }, /* Saturation */ - { 0x05, 0x0a }, /* Contrast */ - { 0x06, 0x95 }, /* Brightness */ - { 0x07, 0x2d }, /* Sharpness */ - { 0x0c, 0x20 }, - { 0x0d, 0x20 }, - { 0x0e, 0x20 }, - { 0x0f, 0x05 }, - { 0x10, 0x9a }, - { 0x11, 0x00 }, /* Pixel clock = fastest */ - { 0x12, 0x24 }, /* Enable AGC and AWB */ - { 0x13, 0x21 }, - { 0x14, 0x80 }, - { 0x15, 0x01 }, - { 0x16, 0x03 }, - { 0x17, 0x38 }, - { 0x18, 0xea }, - { 0x19, 0x04 }, - { 0x1a, 0x93 }, - { 0x1b, 0x00 }, - { 0x1e, 0xc4 }, - { 0x1f, 0x04 }, - { 0x20, 0x20 }, - { 0x21, 0x10 }, - { 0x22, 0x88 }, - { 0x23, 0xc0 }, /* Crystal circuit power level */ - { 0x25, 0x9a }, /* Increase AEC black ratio */ - { 0x26, 0xb2 }, /* BLC enable */ - { 0x27, 0xa2 }, - { 0x28, 0x00 }, - { 0x29, 0x00 }, - { 0x2a, 0x84 }, /* 60 Hz power */ - { 0x2b, 0xa8 }, /* 60 Hz power */ - { 0x2c, 0xa0 }, - { 0x2d, 0x95 }, /* Enable auto-brightness */ - { 0x2e, 0x88 }, - { 0x33, 0x26 }, - { 0x34, 0x03 }, - { 0x36, 0x8f }, - { 0x37, 0x80 }, - { 0x38, 0x83 }, - { 0x39, 0x80 }, - { 0x3a, 0x0f }, - { 0x3b, 0x3c }, - { 0x3c, 0x1a }, - { 0x3d, 0x80 }, - { 0x3e, 0x80 }, - { 0x3f, 0x0e }, - { 0x40, 0x00 }, /* White bal */ - { 0x41, 0x00 }, /* White bal */ - { 0x42, 0x80 }, - { 0x43, 0x3f }, /* White bal */ - { 0x44, 0x80 }, - { 0x45, 0x20 }, - { 0x46, 0x20 }, - { 0x47, 0x80 }, - { 0x48, 0x7f }, - { 0x49, 0x00 }, - { 0x4a, 0x00 }, - { 0x4b, 0x80 }, - { 0x4c, 0xd0 }, - { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */ - { 0x4e, 0x40 }, - { 0x4f, 0x07 }, /* UV avg., col. killer: max */ - { 0x50, 0xff }, - { 0x54, 0x23 }, /* Max AGC gain: 18dB */ - { 0x55, 0xff }, - { 0x56, 0x12 }, - { 0x57, 0x81 }, - { 0x58, 0x75 }, - { 0x59, 0x01 }, /* AGC dark current comp.: +1 */ - { 0x5a, 0x2c }, - { 0x5b, 0x0f }, /* AWB chrominance levels */ - { 0x5c, 0x10 }, - { 0x3d, 0x80 }, - { 0x27, 0xa6 }, - { 0x12, 0x20 }, /* Toggle AWB */ - { 0x12, 0x24 }, - }; - - PDEBUG(D_PROBE, "starting sensor configuration"); - - if (init_ov_sensor(sd) < 0) { - PDEBUG(D_ERR, "Failed to read sensor ID."); - return -1; - } - PDEBUG(D_PROBE, "OV6xx0 sensor detected"); + PDEBUG(D_PROBE, "starting OV6xx0 configuration"); /* Detect sensor (sub)type */ rc = i2c_r(sd, OV7610_REG_COM_I); @@ -1251,15 +1279,6 @@ static int ov6xx0_configure(struct sd *sd) /* Set sensor-specific vars */ sd->sif = 1; - if (sd->sensor == SEN_OV6620) { - PDEBUG(D_PROBE, "Writing 6x20 registers"); - 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, ARRAY_SIZE(norm_6x30))) - return -1; - } return 0; } @@ -1298,22 +1317,31 @@ static int sd_config(struct gspca_dev *gspca_dev, ov51x_led_control(sd, 0); /* turn LED off */ /* Test for 76xx */ - sd->primary_i2c_slave = OV7xx0_SID; if (ov51x_set_slave_ids(sd, OV7xx0_SID) < 0) goto error; /* The OV519 must be more aggressive about sensor detection since * I2C write will never fail if the sensor is not present. We have * to try to initialize the sensor to detect its presence */ - if (init_ov_sensor(sd) < 0) { + if (init_ov_sensor(sd) >= 0) { + if (ov7xx0_configure(sd) < 0) { + PDEBUG(D_ERR, "Failed to configure OV7xx0"); + goto error; + } + } else { + /* Test for 6xx0 */ - sd->primary_i2c_slave = OV6xx0_SID; if (ov51x_set_slave_ids(sd, OV6xx0_SID) < 0) goto error; - if (init_ov_sensor(sd) < 0) { + if (init_ov_sensor(sd) >= 0) { + if (ov6xx0_configure(sd) < 0) { + PDEBUG(D_ERR, "Failed to configure OV6xx0"); + goto error; + } + } else { + /* Test for 8xx0 */ - sd->primary_i2c_slave = OV8xx0_SID; if (ov51x_set_slave_ids(sd, OV8xx0_SID) < 0) goto error; @@ -1321,24 +1349,13 @@ static int sd_config(struct gspca_dev *gspca_dev, PDEBUG(D_ERR, "Can't determine sensor slave IDs"); goto error; - } else { - if (ov8xx0_configure(sd) < 0) { - PDEBUG(D_ERR, - "Failed to configure OV8xx0 sensor"); - goto error; - } } - } else { - if (ov6xx0_configure(sd) < 0) { - PDEBUG(D_ERR, "Failed to configure OV6xx0"); + if (ov8xx0_configure(sd) < 0) { + PDEBUG(D_ERR, + "Failed to configure OV8xx0 sensor"); goto error; } } - } else { - if (ov7xx0_configure(sd) < 0) { - PDEBUG(D_ERR, "Failed to configure OV7xx0"); - goto error; - } } cam = &gspca_dev->cam; @@ -1355,15 +1372,53 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->colors = COLOR_DEF; sd->hflip = HFLIP_DEF; sd->vflip = VFLIP_DEF; + if (sd->sensor != SEN_OV7670) + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) + | (1 << VFLIP_IDX); return 0; error: PDEBUG(D_ERR, "OV519 Config failed"); return -EBUSY; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { + struct sd *sd = (struct sd *) gspca_dev; + + /* initialize the sensor */ + switch (sd->sensor) { + case SEN_OV6620: + if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20))) + return -EIO; + break; + case SEN_OV6630: + if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30))) + return -EIO; + break; + default: +/* case SEN_OV7610: */ +/* case SEN_OV76BE: */ + if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610))) + return -EIO; + break; + case SEN_OV7620: + if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620))) + return -EIO; + break; + case SEN_OV7640: + if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640))) + return -EIO; + break; + case SEN_OV7670: + if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670))) + return -EIO; + break; + case SEN_OV8610: + if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610))) + return -EIO; + break; + } return 0; } @@ -1852,14 +1907,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ov51x_led_control((struct sd *) gspca_dev, 0); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -2116,11 +2163,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c index d9668f4cb..83b5f740c 100644 --- a/linux/drivers/media/video/gspca/pac207.c +++ b/linux/drivers/media/video/gspca/pac207.c @@ -56,12 +56,6 @@ MODULE_LICENSE("GPL"); #define PAC207_GAIN_KNEE 20 #define PAC207_AUTOGAIN_DEADZONE 30 -/* We calculating the autogain at the end of the transfer of a frame, at this - moment a frame with the old settings is being transmitted, and a frame is - being captured with the old settings. So if we adjust the autogain we must - ignore atleast the 2 next frames for the new settings to come into effect - before doing any other adjustments */ -#define PAC207_AUTOGAIN_IGNORE_FRAMES 3 /* specific webcam descriptor */ struct sd { @@ -131,7 +125,8 @@ static struct ctrl sd_ctrls[] = { .minimum = 0, .maximum = 1, .step = 1, - .default_value = 1, +#define AUTOGAIN_DEF 1 + .default_value = AUTOGAIN_DEF, .flags = 0, }, .set = sd_setautogain, @@ -181,9 +176,6 @@ static const __u8 pac207_sensor_init[][8] = { /* 48 reg_72 Rate Control end BalSize_4a =0x36 */ static const __u8 PacReg72[] = { 0x00, 0x00, 0x36, 0x00 }; -static const unsigned char pac207_sof_marker[5] = - { 0xff, 0xff, 0x00, 0xff, 0x96 }; - static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, const u8 *buffer, u16 length) { @@ -259,13 +251,6 @@ static int sd_config(struct gspca_dev *gspca_dev, return -ENODEV; } - pac207_write_reg(gspca_dev, 0x41, 0x00); - /* Bit_0=Image Format, - * Bit_1=LED, - * Bit_2=Compression test mode enable */ - pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ - pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */ - PDEBUG(D_PROBE, "Pixart PAC207BCA Image Processor and Control Chip detected" " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); @@ -277,16 +262,21 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->brightness = PAC207_BRIGHTNESS_DEFAULT; sd->exposure = PAC207_EXPOSURE_DEFAULT; sd->gain = PAC207_GAIN_DEFAULT; + sd->autogain = AUTOGAIN_DEF; return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; + pac207_write_reg(gspca_dev, 0x41, 0x00); + /* Bit_0=Image Format, + * Bit_1=LED, + * Bit_2=Compression test mode enable */ + pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ + pac207_write_reg(gspca_dev, 0x11, 0x30); /* Analog Bias */ - sd->autogain = 1; return 0; } @@ -342,14 +332,8 @@ static void sd_stopN(struct gspca_dev *gspca_dev) pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ -} +/* Include pac common sof detection functions */ +#include "pac_common.h" static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) { @@ -364,33 +348,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE, PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) - sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES; -} - -static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev, - unsigned char *m, int len) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - - /* Search for the SOF marker (fixed part) in the header */ - for (i = 0; i < len; i++) { - if (m[i] == pac207_sof_marker[sd->sof_read]) { - sd->sof_read++; - if (sd->sof_read == sizeof(pac207_sof_marker)) { - PDEBUG(D_STREAM, - "SOF found, bytes to analyze: %u." - " Frame starts at byte #%u", - len, i + 1); - sd->sof_read = 0; - return m + i + 1; - } - } else { - sd->sof_read = 0; - } - } - - return NULL; + sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; } static void sd_pkt_scan(struct gspca_dev *gspca_dev, @@ -401,14 +359,14 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; unsigned char *sof; - sof = pac207_find_sof(gspca_dev, data, len); + sof = pac_find_sof(gspca_dev, data, len); if (sof) { int n; /* finish decoding current frame */ n = sof - data; - if (n > sizeof pac207_sof_marker) - n -= sizeof pac207_sof_marker; + if (n > sizeof pac_sof_marker) + n -= sizeof pac_sof_marker; else n = 0; frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, @@ -536,7 +494,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) sd->gain = PAC207_GAIN_DEFAULT; if (gspca_dev->streaming) { sd->autogain_ignore_frames = - PAC207_AUTOGAIN_IGNORE_FRAMES; + PAC_AUTOGAIN_IGNORE_FRAMES; setexposure(gspca_dev); setgain(gspca_dev); } @@ -559,11 +517,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .dq_callback = pac207_do_auto_gain, .pkt_scan = sd_pkt_scan, }; diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index 94f0cd1b8..296ba82e6 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -19,10 +19,39 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* Some documentation about various registers as determined by trial and error. + When the register addresses differ between the 7202 and the 7311 the 2 + different addresses are written as 7302addr/7311addr, when one of the 2 + addresses is a - sign that register description is not valid for the + matching IC. + + Register page 1: + + Address Description + -/0x08 Unknown compressor related, must always be 8 except when not + in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 ! + -/0x1b Auto white balance related, bit 0 is AWB enable (inverted) + bits 345 seem to toggle per color gains on/off (inverted) + 0x78 Global control, bit 6 controls the LED (inverted) + -/0x80 JPEG compression ratio ? Best not touched + + Register page 3/4: + + Address Description + 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on + the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? + -/0x0f Master gain 1-245, low value = high gain + 0x10/- Master gain 0-31 + -/0x10 Another gain 0-15, limited influence (1-2x gain I guess) + 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused + -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to + completely disable the analog amplification block. Set to 0x68 + for max gain, 0x14 for minimal gain. +*/ + #define MODULE_NAME "pac7311" #include "gspca.h" -#include "jpeg.h" MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); MODULE_DESCRIPTION("Pixart PAC7311"); @@ -32,25 +61,23 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - int lum_sum; - atomic_t avg_lum; - atomic_t do_gain; - unsigned char brightness; unsigned char contrast; unsigned char colors; + unsigned char gain; + unsigned char exposure; unsigned char autogain; __u8 hflip; __u8 vflip; - __u8 qindex; - - 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 + + u8 sof_read; + u8 autogain_ignore_frames; + + atomic_t avg_lum; }; /* V4L2 controls supported by the driver */ @@ -66,8 +93,14 @@ 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 int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { +/* This control is pac7302 only */ +#define BRIGHTNESS_IDX 0 { { .id = V4L2_CID_BRIGHTNESS, @@ -83,6 +116,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setbrightness, .get = sd_getbrightness, }, +/* This control is for both the 7302 and the 7311 */ { { .id = V4L2_CID_CONTRAST, @@ -92,12 +126,14 @@ static struct ctrl sd_ctrls[] = { #define CONTRAST_MAX 255 .maximum = CONTRAST_MAX, .step = 1, -#define CONTRAST_DEF 60 +#define CONTRAST_DEF 127 .default_value = CONTRAST_DEF, }, .set = sd_setcontrast, .get = sd_getcontrast, }, +/* This control is pac7302 only */ +#define SATURATION_IDX 2 { { .id = V4L2_CID_SATURATION, @@ -113,6 +149,39 @@ static struct ctrl sd_ctrls[] = { .set = sd_setcolors, .get = sd_getcolors, }, +/* All controls below are for both the 7302 and the 7311 */ + { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Gain", + .minimum = 0, +#define GAIN_MAX 255 + .maximum = GAIN_MAX, + .step = 1, +#define GAIN_DEF 127 +#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */ + .default_value = GAIN_DEF, + }, + .set = sd_setgain, + .get = sd_getgain, + }, + { + { + .id = V4L2_CID_EXPOSURE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Exposure", + .minimum = 0, +#define EXPOSURE_MAX 255 + .maximum = EXPOSURE_MAX, + .step = 1, +#define EXPOSURE_DEF 16 /* 32 ms / 30 fps */ +#define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */ + .default_value = EXPOSURE_DEF, + }, + .set = sd_setexposure, + .get = sd_getexposure, + }, { { .id = V4L2_CID_AUTOGAIN, @@ -127,7 +196,6 @@ static struct ctrl sd_ctrls[] = { .set = sd_setautogain, .get = sd_getautogain, }, -/* next controls work with pac7302 only */ { { .id = V4L2_CID_HFLIP, @@ -177,7 +245,7 @@ static struct v4l2_pix_format vga_mode[] = { }; /* pac 7302 */ -static const __u8 probe_7302[] = { +static const __u8 init_7302[] = { /* index,value */ 0xff, 0x01, /* page 1 */ 0x78, 0x00, /* deactivate */ @@ -243,7 +311,7 @@ static const __u8 start_7302[] = { 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 */ + 0xff, 1, 0x01, /* page 1 */ 0x78, 1, 0x00, 0, 0 /* end of sequence */ }; @@ -273,10 +341,10 @@ static const __u8 page3_7302[] = { }; /* 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 */ +static const __u8 init_7311[] = { + 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */ + 0x78, 0x40, /* Bit_0=start stream, Bit_6=LED */ + 0x78, 0x44, /* Bit_0=start stream, Bit_6=LED */ 0xff, 0x04, 0x27, 0x80, 0x28, 0xca, @@ -321,7 +389,7 @@ static const __u8 page4_7311[] = { 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, + 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x68, 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00, 0x23, 0x28, 0x04, 0x11, 0x00, 0x00 }; @@ -340,6 +408,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev, 500); } +#if 0 /* not used */ static __u8 reg_r(struct gspca_dev *gspca_dev, __u8 index) { @@ -352,6 +421,7 @@ static __u8 reg_r(struct gspca_dev *gspca_dev, 500); return gspca_dev->usb_buf[0]; } +#endif static void reg_w(struct gspca_dev *gspca_dev, __u8 index, @@ -362,7 +432,7 @@ static void reg_w(struct gspca_dev *gspca_dev, usb_sndctrlpipe(gspca_dev->dev, 0), 0, /* request */ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, gspca_dev->usb_buf, 1, + 0, index, gspca_dev->usb_buf, 1, 500); } @@ -413,7 +483,7 @@ static void reg_w_var(struct gspca_dev *gspca_dev, reg_w_page(gspca_dev, page3_7302, sizeof page3_7302); break; default: - if (len > 32) { + if (len > 64) { PDEBUG(D_ERR|D_STREAM, "Incorrect variable sequence"); return; @@ -447,30 +517,28 @@ static int sd_config(struct gspca_dev *gspca_dev, 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); + gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) + | (1 << SATURATION_IDX); } sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; sd->colors = COLOR_DEF; + sd->gain = GAIN_DEF; + sd->exposure = EXPOSURE_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 */ +/* This function is used by pac7302 only */ static void setbrightcont(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -497,98 +565,127 @@ static void setbrightcont(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0xdc, 0x01); } -static void setbrightness(struct gspca_dev *gspca_dev) +/* This function is used by pac7311 only */ +static void setcontrast(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, 0x0f, brightness); + reg_w(gspca_dev, 0x10, sd->contrast >> 4); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); - PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness); } -static void setcontrast(struct gspca_dev *gspca_dev) +/* This function is used by pac7302 only */ +static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + 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}; - if (sd->sensor == SENSOR_PAC7302) { - setbrightcont(gspca_dev); - return; - } - reg_w(gspca_dev, 0xff, 0x01); - reg_w(gspca_dev, 0x10, sd->contrast); - /* load registers to sensor (Bit 0, auto clear) */ + 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); + PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setgain(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, 0x03); /* page 3 */ + reg_w(gspca_dev, 0x10, sd->gain >> 3); + } else { + int gain = GAIN_MAX - sd->gain; + if (gain < 1) + gain = 1; + else if (gain > 245) + gain = 245; + reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ + reg_w(gspca_dev, 0x0e, 0x00); + reg_w(gspca_dev, 0x0f, gain); } - reg_w(gspca_dev, 0xff, 0x01); - 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) +static void setexposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + __u8 reg; - if (sd->autogain) { - sd->lum_sum = 0; - sd->ag_cnt = AG_CNT_START; + /* register 2 of frame 3/4 contains the clock divider configuring the + no fps according to the formula: 60 / reg. sd->exposure is the + desired exposure time in ms. */ + reg = 120 * sd->exposure / 1000; + if (reg < 2) + reg = 2; + else if (reg > 63) + reg = 63; + + if (sd->sensor == SENSOR_PAC7302) { + /* On the pac7302 reg2 MUST be a multiple of 3, so round it to + the nearest multiple of 3, except when between 6 and 12? */ + if (reg < 6 || reg > 12) + reg = ((reg + 1) / 3) * 3; + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + reg_w(gspca_dev, 0x02, reg); } else { - sd->ag_cnt = -1; + reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ + reg_w(gspca_dev, 0x02, reg); + /* Page 1 register 8 must always be 0x08 except when not in + 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */ + reg_w(gspca_dev, 0xff, 0x01); + if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv && + reg <= 3) + reg_w(gspca_dev, 0x08, 0x09); + else + reg_w(gspca_dev, 0x08, 0x08); } + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); } -/* 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); + if (sd->sensor == SENSOR_PAC7302) { + reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ + data = (sd->hflip ? 0x08 : 0x00) + | (sd->vflip ? 0x04 : 0x00); + } else { + reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ + data = (sd->hflip ? 0x04 : 0x00) + | (sd->vflip ? 0x08 : 0x00); + } reg_w(gspca_dev, 0x21, data); + /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { - reg_w(gspca_dev, 0x78, 0x44); /* Turn on LED */ + struct sd *sd = (struct sd *) gspca_dev; + + if (sd->sensor == SENSOR_PAC7302) + reg_w_seq(gspca_dev, init_7302, sizeof init_7302); + else + reg_w_seq(gspca_dev, init_7311, sizeof init_7311); + return 0; } @@ -596,60 +693,51 @@ static void sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - sd->tosof = 0; + sd->sof_read = 0; - if (sd->sensor == SENSOR_PAC7302) + if (sd->sensor == SENSOR_PAC7302) { reg_w_var(gspca_dev, start_7302); - else + setbrightcont(gspca_dev); + setcolors(gspca_dev); + } else { reg_w_var(gspca_dev, start_7311); - - setcontrast(gspca_dev); - setbrightness(gspca_dev); - setcolors(gspca_dev); - setautogain(gspca_dev); + setcontrast(gspca_dev); + } + setgain(gspca_dev); + setexposure(gspca_dev); + sethvflip(gspca_dev); /* set correct resolution */ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { 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, 0x87, 0x10); break; case 1: /* 320x240 pac7311 */ - reg_w(gspca_dev, 0xff, 0x04); - 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, 0x87, 0x11); break; case 0: /* 640x480 */ if (sd->sensor == SENSOR_PAC7302) break; - reg_w(gspca_dev, 0xff, 0x04); - 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, 0x87, 0x12); break; } + sd->sof_read = 0; + sd->autogain_ignore_frames = 0; + atomic_set(&sd->avg_lum, -1); + /* start stream */ reg_w(gspca_dev, 0xff, 0x01); - if (sd->sensor == SENSOR_PAC7302) { - sethvflip(gspca_dev); - reg_w(gspca_dev, 0x78, 0x01); - reg_w(gspca_dev, 0xff, 0x01); + if (sd->sensor == SENSOR_PAC7302) reg_w(gspca_dev, 0x78, 0x01); - } else { - reg_w(gspca_dev, 0x78, 0x44); - reg_w(gspca_dev, 0x78, 0x45); - } + else + reg_w(gspca_dev, 0x78, 0x05); } static void sd_stopN(struct gspca_dev *gspca_dev) @@ -657,6 +745,7 @@ 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, 0xff, 0x01); reg_w(gspca_dev, 0x78, 0x00); reg_w(gspca_dev, 0x78, 0x00); return; @@ -668,9 +757,9 @@ 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, 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 */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ + reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ } static void sd_stop0(struct gspca_dev *gspca_dev) @@ -683,49 +772,51 @@ static void sd_stop0(struct gspca_dev *gspca_dev) } } -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ -} +/* Include pac common sof detection functions */ +#include "pac_common.h" 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; + int avg_lum = atomic_read(&sd->avg_lum); + int desired_lum, deadzone; - if (!atomic_read(&sd->do_gain)) + if (avg_lum == -1) 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 || - luma > luma_mean + luma_delta) { - Gbright += (luma_mean - luma) >> spring; - if (Gbright > 0x1a) - Gbright = 0x1a; - else if (Gbright < 4) - Gbright = 4; - PDEBUG(D_FRAM, "gbright %d", Gbright); - 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); - } + + if (sd->sensor == SENSOR_PAC7302) { + desired_lum = 270 + sd->brightness * 4; + /* Hack hack, with the 7202 the first exposure step is + pretty large, so if we're about to make the first + exposure increase make the deadzone large to avoid + oscilating */ + if (desired_lum > avg_lum && sd->gain == GAIN_DEF && + sd->exposure > EXPOSURE_DEF && + sd->exposure < 42) + deadzone = 90; + else + deadzone = 30; + } else { + desired_lum = 200; + deadzone = 20; } + + if (sd->autogain_ignore_frames > 0) + sd->autogain_ignore_frames--; + else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, + deadzone, GAIN_KNEE, EXPOSURE_KNEE)) + sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; } +static const unsigned char pac7311_jpeg_header1[] = { + 0xff, 0xd8, 0xff, 0xc0, 0x00, 0x11, 0x08 +}; + +static const unsigned char pac7311_jpeg_header2[] = { + 0x03, 0x01, 0x21, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xda, + 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 +}; + /* this function is run at interrupt level */ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ @@ -733,98 +824,71 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, int len) /* iso packet length */ { struct sd *sd = (struct sd *) gspca_dev; - 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; - } - sprintf(&tmp[(i % 16) * 3], "%02x ", data[i]); + unsigned char *sof; + + sof = pac_find_sof(gspca_dev, data, len); + if (sof) { + unsigned char tmpbuf[4]; + int n, lum_offset, footer_length; + + if (sd->sensor == SENSOR_PAC7302) { + /* 6 bytes after the FF D9 EOF marker a number of lumination + bytes are send corresponding to different parts of the + image, the 14th and 15th byte after the EOF seem to + correspond to the center of the image */ + lum_offset = 61 + sizeof pac_sof_marker; + footer_length = 74; + } else { + lum_offset = 24 + sizeof pac_sof_marker; + footer_length = 26; } - if (tmp[0] != 0) - PDEBUG(0x200, "%s", tmp); - } -#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; 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-*/ + /* Finish decoding current frame */ + n = (sof - data) - (footer_length + sizeof pac_sof_marker); + if (n < 0) { + frame->data_end += n; + n = 0; + } + frame = gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, n); + if (gspca_dev->last_packet_type != DISCARD_PACKET && + frame->data_end[-2] == 0xff && + frame->data_end[-1] == 0xd9) + frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, + NULL, 0); + + n = sof - data; + len -= n; + data = sof; + + /* Get average lumination */ + if (gspca_dev->last_packet_type == LAST_PACKET && + n >= lum_offset) + atomic_set(&sd->avg_lum, data[-lum_offset] + + data[-lum_offset + 1]); + else + atomic_set(&sd->avg_lum, -1); + + /* Start the new frame with the jpeg header */ + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, + pac7311_jpeg_header1, sizeof(pac7311_jpeg_header1)); + if (sd->sensor == SENSOR_PAC7302) { + /* The PAC7302 has the image rotated 90 degrees */ + tmpbuf[0] = gspca_dev->width >> 8; + tmpbuf[1] = gspca_dev->width & 0xff; + tmpbuf[2] = gspca_dev->height >> 8; + tmpbuf[3] = gspca_dev->height & 0xff; + } else { + 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, + pac7311_jpeg_header2, sizeof(pac7311_jpeg_header2)); } - gspca_frame_add(gspca_dev, INTER_PACKET, - frame, data, i); + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) @@ -833,7 +897,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) sd->brightness = val; if (gspca_dev->streaming) - setbrightness(gspca_dev); + setbrightcont(gspca_dev); return 0; } @@ -850,8 +914,12 @@ 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) { + if (sd->sensor == SENSOR_PAC7302) + setbrightcont(gspca_dev); + else + setcontrast(gspca_dev); + } return 0; } @@ -881,13 +949,62 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +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; +} + +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; +} + static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; sd->autogain = val; - if (gspca_dev->streaming) - setautogain(gspca_dev); + /* when switching to autogain set defaults to make sure + we are on a valid point of the autogain gain / + exposure knee graph, and give this change time to + take effect before doing autogain. */ + if (sd->autogain) { + sd->exposure = EXPOSURE_DEF; + sd->gain = GAIN_DEF; + if (gspca_dev->streaming) { + sd->autogain_ignore_frames = + PAC_AUTOGAIN_IGNORE_FRAMES; + setexposure(gspca_dev); + setgain(gspca_dev); + } + } + return 0; } @@ -941,11 +1058,10 @@ static struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, }; @@ -959,6 +1075,9 @@ static __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302}, + {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302}, + {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302}, + {USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/linux/drivers/media/video/gspca/pac_common.h b/linux/drivers/media/video/gspca/pac_common.h new file mode 100644 index 000000000..34d4b1494 --- /dev/null +++ b/linux/drivers/media/video/gspca/pac_common.h @@ -0,0 +1,60 @@ +/* + * Pixart PAC207BCA / PAC73xx common functions + * + * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> + * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li + * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr + * + * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +/* We calculate the autogain at the end of the transfer of a frame, at this + moment a frame with the old settings is being transmitted, and a frame is + being captured with the old settings. So if we adjust the autogain we must + ignore atleast the 2 next frames for the new settings to come into effect + before doing any other adjustments */ +#define PAC_AUTOGAIN_IGNORE_FRAMES 3 + +static const unsigned char pac_sof_marker[5] = + { 0xff, 0xff, 0x00, 0xff, 0x96 }; + +static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev, + unsigned char *m, int len) +{ + struct sd *sd = (struct sd *) gspca_dev; + int i; + + /* Search for the SOF marker (fixed part) in the header */ + for (i = 0; i < len; i++) { + if (m[i] == pac_sof_marker[sd->sof_read]) { + sd->sof_read++; + if (sd->sof_read == sizeof(pac_sof_marker)) { + PDEBUG(D_FRAM, + "SOF found, bytes to analyze: %u." + " Frame starts at byte #%u", + len, i + 1); + sd->sof_read = 0; + return m + i + 1; + } + } else { + sd->sof_read = 0; + } + } + + return NULL; +} diff --git a/linux/drivers/media/video/gspca/sonixb.c b/linux/drivers/media/video/gspca/sonixb.c index afbb969ba..53cb724bf 100644 --- a/linux/drivers/media/video/gspca/sonixb.c +++ b/linux/drivers/media/video/gspca/sonixb.c @@ -20,6 +20,26 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* Some documentation on known sonixb registers: + +Reg Use +0x10 high nibble red gain low nibble blue gain +0x11 low nibble green gain +0x12 hstart +0x13 vstart +0x15 hsize (hsize = register-value * 16) +0x16 vsize (vsize = register-value * 16) +0x17 bit 0 toggle compression quality (according to sn9c102 driver) +0x18 bit 7 enables compression, bit 4-5 set image down scaling: + 00 scale 1, 01 scale 1/2, 10, scale 1/4 +0x19 high-nibble is sensor clock divider, changes exposure on sensors which + use a clock generated by the bridge. Some sensors have their own clock. +0x1c auto_exposure area (for avg_lum) startx (startx = register-value * 32) +0x1d auto_exposure area (for avg_lum) starty (starty = register-value * 32) +0x1e auto_exposure area (for avg_lum) stopx (hsize = (0x1e - 0x1c) * 32) +0x1f auto_exposure area (for avg_lum) stopy (vsize = (0x1f - 0x1d) * 32) +*/ + #define MODULE_NAME "sonixb" #include "gspca.h" @@ -31,10 +51,8 @@ MODULE_LICENSE("GPL"); /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - - struct sd_desc sd_desc; /* our nctrls differ dependend upon the - sensor, so we use a per cam copy */ atomic_t avg_lum; + int prev_avg_lum; unsigned char gain; unsigned char exposure; @@ -44,8 +62,12 @@ struct sd { unsigned char frames_to_drop; unsigned char freq; /* light freq filter setting */ - unsigned char fr_h_sz; /* size of frame header */ - char sensor; /* Type of image sensor chip */ + __u8 bridge; /* Type of bridge */ +#define BRIDGE_101 0 +#define BRIDGE_102 0 /* We make no difference between 101 and 102 */ +#define BRIDGE_103 1 + + __u8 sensor; /* Type of image sensor chip */ #define SENSOR_HV7131R 0 #define SENSOR_OV6650 1 #define SENSOR_OV7630 2 @@ -53,16 +75,35 @@ struct sd { #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 */ +typedef const __u8 sensor_init_t[8]; + +struct sensor_data { + const __u8 *bridge_init[2]; + int bridge_init_size[2]; + sensor_init_t *sensor_init; + int sensor_init_size; + sensor_init_t *sensor_bridge_init[2]; + int sensor_bridge_init_size[2]; + int flags; + unsigned ctrl_dis; + __u8 sensor_addr; +}; + +/* sensor_data flags */ #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 F_SIF 0x02 /* sif or vga */ + +/* priv field of struct v4l2_pix_format flags (do not use low nibble!) */ +#define MODE_RAW 0x10 /* raw bayer mode */ +#define MODE_REDUCED_SIF 0x20 /* vga mode (320x240 / 160x120) on sif cam */ + +/* ctrl_dis helper macros */ +#define NO_EXPO ((1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)) +#define NO_FREQ (1 << FREQ_IDX) +#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX) #define COMP2 0x8f #define COMP 0xc7 /* 0x87 //0x07 */ @@ -73,6 +114,18 @@ struct sd { #define SYS_CLK 0x04 +#define SENS(bridge_1, bridge_3, sensor, sensor_1, \ + sensor_3, _flags, _ctrl_dis, _sensor_addr) \ +{ \ + .bridge_init = { bridge_1, bridge_3 }, \ + .bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \ + .sensor_init = sensor, \ + .sensor_init_size = sizeof(sensor), \ + .sensor_bridge_init = { sensor_1, sensor_3,}, \ + .sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \ + .flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \ +} + /* We calculate the autogain at the end of the transfer of a frame, at this moment a frame with the old settings is being transmitted, and a frame is being captured with the old settings. So if we adjust the autogain we must @@ -95,6 +148,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val); static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { +#define BRIGHTNESS_IDX 0 { { .id = V4L2_CID_BRIGHTNESS, @@ -109,6 +163,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setbrightness, .get = sd_getbrightness, }, +#define GAIN_IDX 1 { { .id = V4L2_CID_GAIN, @@ -124,6 +179,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setgain, .get = sd_getgain, }, +#define EXPOSURE_IDX 2 { { .id = V4L2_CID_EXPOSURE, @@ -140,6 +196,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setexposure, .get = sd_getexposure, }, +#define AUTOGAIN_IDX 3 { { .id = V4L2_CID_AUTOGAIN, @@ -155,6 +212,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setautogain, .get = sd_getautogain, }, +#define FREQ_IDX 4 { { .id = V4L2_CID_POWER_LINE_FREQUENCY, @@ -172,31 +230,56 @@ static struct ctrl sd_ctrls[] = { }; static struct v4l2_pix_format vga_mode[] = { - {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120, .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2 | MODE_RAW}, + {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, .priv = 2}, {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, .bytesperline = 320, - .sizeimage = 320 * 240, + .sizeimage = 320 * 240 * 5 / 4, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, {640, 480, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, .bytesperline = 640, - .sizeimage = 640 * 480, + .sizeimage = 640 * 480 * 5 / 4, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; static struct v4l2_pix_format sif_mode[] = { - {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 | MODE_RAW | MODE_REDUCED_SIF}, + {160, 120, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 | MODE_REDUCED_SIF}, + {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 176, .sizeimage = 176 * 144, .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 | MODE_RAW}, + {176, 144, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, + {320, 240, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240 * 5 / 4, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 | MODE_REDUCED_SIF}, {352, 288, V4L2_PIX_FMT_SN9C10X, V4L2_FIELD_NONE, .bytesperline = 352, - .sizeimage = 352 * 288, + .sizeimage = 352 * 288 * 5 / 4, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; @@ -204,7 +287,7 @@ static struct v4l2_pix_format sif_mode[] = { static const __u8 initHv7131[] = { 0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, /* shift from 0x02 0x01 0x00 */ + 0x00, 0x00, 0x00, 0x02, 0x01, 0x00, 0x28, 0x1e, 0x60, 0x8a, 0x20, 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c }; @@ -219,13 +302,13 @@ static const __u8 initOv6650[] = { #if 1 0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x0b, - 0x10, 0x1d, 0x10, 0x00, 0x06, 0x1f, 0x00 + 0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b, + 0x10, 0x1d, 0x10, 0x02, 0x02, 0x09, 0x07 #else /* old version? */ 0x64, 0x44, 0x28, 0x00, 0x00, 0x00, 0x00, 0x10, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x01, 0x0a, 0x14, 0x0f, 0x68, 0x8b, + 0x00, 0x01, 0x01, 0x0a, 0x14, 0x0f, 0x68, 0x8b, 0x10, 0x1d, 0x10, 0x01, 0x01, 0x07, 0x06 #endif }; @@ -283,22 +366,19 @@ static const __u8 ov6650_sensor_init[][8] = static const __u8 initOv7630[] = { 0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */ -#if 1 - 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */ + 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */ 0x28, 0x1e, /* H & V sizes r15 .. r16 */ - 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */ + 0x68, COMP2, MCK_INIT1, /* r17 .. r19 */ +#if 1 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */ #else /* jfm from win */ - 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */ - 0x16, 0x12, /* H & V sizes r15 .. r16 */ - 0x68, COMP2, MCK_INIT1, /* r17 .. r19 */ 0x1d, 0x10, 0x06, 0x01, 0x00, 0x03 /* r1a .. r1f */ #endif }; static const __u8 initOv7630_3[] = { 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */ 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */ - 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */ + 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */ 0x28, 0x1e, /* H & V sizes r15 .. r16 */ 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */ 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */ @@ -327,47 +407,65 @@ static const __u8 ov7630_sensor_init[][8] = { {0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10}, }; +static const __u8 ov7630_sensor_init_3[][8] = { + {0xa0, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10}, +}; + static const __u8 initPas106[] = { 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, 0x01, 0x00, - 0x16, 0x12, 0x28, COMP1, MCK_INIT1, - 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c + 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, + 0x16, 0x12, 0x24, COMP1, MCK_INIT1, + 0x18, 0x10, 0x02, 0x02, 0x09, 0x07 }; /* compression 0x86 mckinit1 0x2b */ -static const __u8 pas106_data[][2] = { - {0x02, 0x04}, /* Pixel Clock Divider 6 */ - {0x03, 0x13}, /* Frame Time MSB */ -/* {0x03, 0x12}, * Frame Time MSB */ - {0x04, 0x06}, /* Frame Time LSB */ -/* {0x04, 0x05}, * Frame Time LSB */ - {0x05, 0x65}, /* Shutter Time Line Offset */ -/* {0x05, 0x6d}, * Shutter Time Line Offset */ -/* {0x06, 0xb1}, * Shutter Time Pixel Offset */ - {0x06, 0xcd}, /* Shutter Time Pixel Offset */ - {0x07, 0xc1}, /* Black Level Subtract Sign */ -/* {0x07, 0x00}, * Black Level Subtract Sign */ - {0x08, 0x06}, /* Black Level Subtract Level */ - {0x08, 0x06}, /* Black Level Subtract Level */ -/* {0x08, 0x01}, * Black Level Subtract Level */ - {0x09, 0x05}, /* Color Gain B Pixel 5 a */ - {0x0a, 0x04}, /* Color Gain G1 Pixel 1 5 */ - {0x0b, 0x04}, /* Color Gain G2 Pixel 1 0 5 */ - {0x0c, 0x05}, /* Color Gain R Pixel 3 1 */ - {0x0d, 0x00}, /* Color GainH Pixel */ - {0x0e, 0x0e}, /* Global Gain */ - {0x0f, 0x00}, /* Contrast */ - {0x10, 0x06}, /* H&V synchro polarity */ - {0x11, 0x06}, /* ?default */ - {0x12, 0x06}, /* DAC scale */ - {0x14, 0x02}, /* ?default */ - {0x13, 0x01}, /* Validate Settings */ +static const __u8 pas106_sensor_init[][8] = { + /* Pixel Clock Divider 6 */ + { 0xa1, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x14 }, + /* Frame Time MSB (also seen as 0x12) */ + { 0xa1, 0x40, 0x03, 0x13, 0x00, 0x00, 0x00, 0x14 }, + /* Frame Time LSB (also seen as 0x05) */ + { 0xa1, 0x40, 0x04, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* Shutter Time Line Offset (also seen as 0x6d) */ + { 0xa1, 0x40, 0x05, 0x65, 0x00, 0x00, 0x00, 0x14 }, + /* Shutter Time Pixel Offset (also seen as 0xb1) */ + { 0xa1, 0x40, 0x06, 0xcd, 0x00, 0x00, 0x00, 0x14 }, + /* Black Level Subtract Sign (also seen 0x00) */ + { 0xa1, 0x40, 0x07, 0xc1, 0x00, 0x00, 0x00, 0x14 }, + /* Black Level Subtract Level (also seen 0x01) */ + { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 }, + { 0xa1, 0x40, 0x08, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain B Pixel 5 a */ + { 0xa1, 0x40, 0x09, 0x05, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain G1 Pixel 1 5 */ + { 0xa1, 0x40, 0x0a, 0x04, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain G2 Pixel 1 0 5 */ + { 0xa1, 0x40, 0x0b, 0x04, 0x00, 0x00, 0x00, 0x14 }, + /* Color Gain R Pixel 3 1 */ + { 0xa1, 0x40, 0x0c, 0x05, 0x00, 0x00, 0x00, 0x14 }, + /* Color GainH Pixel */ + { 0xa1, 0x40, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x14 }, + /* Global Gain */ + { 0xa1, 0x40, 0x0e, 0x0e, 0x00, 0x00, 0x00, 0x14 }, + /* Contrast */ + { 0xa1, 0x40, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14 }, + /* H&V synchro polarity */ + { 0xa1, 0x40, 0x10, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* ?default */ + { 0xa1, 0x40, 0x11, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* DAC scale */ + { 0xa1, 0x40, 0x12, 0x06, 0x00, 0x00, 0x00, 0x14 }, + /* ?default */ + { 0xa1, 0x40, 0x14, 0x02, 0x00, 0x00, 0x00, 0x14 }, + /* Validate Settings */ + { 0xa1, 0x40, 0x13, 0x01, 0x00, 0x00, 0x00, 0x14 }, }; + static const __u8 initPas202[] = { 0x44, 0x44, 0x21, 0x30, 0x00, 0x00, 0x00, 0x80, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, 0x03, 0x0a, /* 6 */ - 0x28, 0x1e, 0x28, 0x89, 0x30, + 0x00, 0x00, 0x00, 0x06, 0x03, 0x0a, + 0x28, 0x1e, 0x28, 0x89, 0x20, 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c }; static const __u8 pas202_sensor_init[][8] = { @@ -397,7 +495,7 @@ static const __u8 pas202_sensor_init[][8] = { static const __u8 initTas5110[] = { 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x46, 0x09, 0x0a, /* shift from 0x45 0x09 0x0a */ + 0x00, 0x01, 0x00, 0x45, 0x09, 0x0a, 0x16, 0x12, 0x60, 0x86, 0x2b, 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07 }; @@ -410,7 +508,7 @@ static const __u8 tas5110_sensor_init[][8] = { static const __u8 initTas5130[] = { 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x01, 0x00, 0x69, 0x0c, 0x0a, + 0x00, 0x01, 0x00, 0x68, 0x0c, 0x0a, 0x28, 0x1e, 0x60, COMP, MCK_INIT, 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c }; @@ -422,6 +520,21 @@ static const __u8 tas5130_sensor_init[][8] = { {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10}, }; +static struct sensor_data sensor_data[] = { +SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0), +SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60), +SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3, + F_GAIN, 0, 0x21), +SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_SIF, NO_EXPO|NO_FREQ, + 0), +SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, 0, + NO_EXPO|NO_FREQ, 0), +SENS(initTas5110, NULL, tas5110_sensor_init, NULL, NULL, F_GAIN|F_SIF, + NO_BRIGHTNESS|NO_FREQ, 0), +SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, + 0), +}; + /* get one byte in gspca_dev->usb_buf */ static void reg_r(struct gspca_dev *gspca_dev, __u16 value) @@ -442,7 +555,7 @@ static void reg_w(struct gspca_dev *gspca_dev, int len) { #ifdef GSPCA_DEBUG - if (len > sizeof gspca_dev->usb_buf) { + if (len > USB_BUF_SZ) { PDEBUG(D_ERR|D_PACK, "reg_w: buffer overflow"); return; } @@ -458,26 +571,6 @@ static void reg_w(struct gspca_dev *gspca_dev, 500); } -static void reg_w_big(struct gspca_dev *gspca_dev, - __u16 value, - const __u8 *buffer, - int len) -{ - __u8 *tmpbuf; - - tmpbuf = kmalloc(len, GFP_KERNEL); - memcpy(tmpbuf, buffer, len); - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, - 0, /* index */ - tmpbuf, len, - 500); - kfree(tmpbuf); -} - static int i2c_w(struct gspca_dev *gspca_dev, const __u8 *buffer) { int retry = 60; @@ -520,7 +613,7 @@ static void setbrightness(struct gspca_dev *gspca_dev) {0xa0, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x10}; /* change reg 0x06 */ - i2cOV[1] = sd->sensor_addr; + i2cOV[1] = sensor_data[sd->sensor].sensor_addr; i2cOV[3] = sd->brightness; if (i2c_w(gspca_dev, i2cOV) < 0) goto err; @@ -578,9 +671,6 @@ static void setbrightness(struct gspca_dev *gspca_dev) goto err; break; } - case SENSOR_TAS5110: - /* FIXME figure out howto control brightness on TAS5110 */ - break; } return; err: @@ -610,7 +700,7 @@ static void setsensorgain(struct gspca_dev *gspca_dev) case SENSOR_OV7630: { __u8 i2c[] = {0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; - i2c[1] = sd->sensor_addr; + i2c[1] = sensor_data[sd->sensor].sensor_addr; i2c[3] = gain >> 2; if (i2c_w(gspca_dev, i2c) < 0) goto err; @@ -637,7 +727,7 @@ static void setgain(struct gspca_dev *gspca_dev) rgb_value = gain; reg_w(gspca_dev, 0x11, &rgb_value, 1); - if (sd->sensor_has_gain) + if (sensor_data[sd->sensor].flags & F_GAIN) setsensorgain(gspca_dev); } @@ -698,6 +788,11 @@ static void setexposure(struct gspca_dev *gspca_dev) else if (reg11 > 16) reg11 = 16; + /* 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; + /* frame exposure time in ms = 1000 * reg11 / 30 -> reg10 = sd->exposure * 2 * reg10_max / (1000 * reg11 / 30) */ reg10 = (sd->exposure * 60 * reg10_max) / (1000 * reg11); @@ -711,13 +806,8 @@ 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[1] = sensor_data[sd->sensor].sensor_addr; i2c[3] = reg10; i2c[4] |= reg11 - 1; @@ -757,7 +847,7 @@ static void setfreq(struct gspca_dev *gspca_dev) ? 0x4f : 0x8a; break; } - i2c[1] = sd->sensor_addr; + i2c[1] = sensor_data[sd->sensor].sensor_addr; if (i2c_w(gspca_dev, i2c) < 0) PDEBUG(D_ERR, "i2c error setfreq"); break; @@ -790,30 +880,19 @@ static int sd_config(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; - 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; + reg_r(gspca_dev, 0x00); + if (gspca_dev->usb_buf[0] != 0x10) + return -ENODEV; /* 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; + sd->sensor = id->driver_info >> 8; + sd->bridge = id->driver_info & 0xff; + gspca_dev->ctrl_dis = sensor_data[sd->sensor].ctrl_dis; cam = &gspca_dev->cam; cam->epaddr = 0x01; - if (!sif) { + if (!(sensor_data[sd->sensor].flags & F_SIF)) { cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); } else { @@ -823,157 +902,98 @@ 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; + if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX)) + sd->autogain = 0; /* Disable do_autogain callback */ + else + sd->autogain = AUTOGAIN_DEF; sd->freq = FREQ_DEF; return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { - reg_r(gspca_dev, 0x00); - if (gspca_dev->usb_buf[0] != 0x10) - return -ENODEV; - return 0; -} + const __u8 stop = 0x09; /* Disable stream turn of LED */ -static void pas106_i2cinit(struct gspca_dev *gspca_dev) -{ - int i; - const __u8 *data; - __u8 i2c1[] = { 0xa1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14 }; - - i = ARRAY_SIZE(pas106_data); - data = pas106_data[0]; - while (--i >= 0) { - memcpy(&i2c1[2], data, 2); - /* copy 2 bytes from the template */ - if (i2c_w(gspca_dev, i2c1) < 0) - PDEBUG(D_ERR, "i2c error pas106"); - data += 2; - } + reg_w(gspca_dev, 0x01, &stop, 1); + + return 0; } /* -- start the camera -- */ static void sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - int mode, l = 0x1f; + struct cam *cam = &gspca_dev->cam; + int mode, l; const __u8 *sn9c10x; - __u8 reg17_19[3]; - - mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; + __u8 reg12_19[8]; + + mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07; + sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge]; + l = sensor_data[sd->sensor].bridge_init_size[sd->bridge]; + memcpy(reg12_19, &sn9c10x[0x12 - 1], 8); + reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4); + /* Special cases where reg 17 and or 19 value depends on mode */ switch (sd->sensor) { - case SENSOR_HV7131R: - sn9c10x = initHv7131; - reg17_19[0] = 0x60; - reg17_19[1] = (mode << 4) | 0x8a; - reg17_19[2] = 0x20; - break; - case SENSOR_OV6650: - sn9c10x = initOv6650; - reg17_19[0] = 0x68; - reg17_19[1] = (mode << 4) | 0x8b; - reg17_19[2] = 0x20; - break; - case SENSOR_OV7630: - 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; - break; - case SENSOR_PAS106: - sn9c10x = initPas106; - reg17_19[0] = 0x24; /* 0x28 */ - reg17_19[1] = (mode << 4) | COMP1; - reg17_19[2] = MCK_INIT1; - break; case SENSOR_PAS202: - sn9c10x = initPas202; - reg17_19[0] = mode ? 0x24 : 0x20; - reg17_19[1] = (mode << 4) | 0x89; - reg17_19[2] = 0x20; - break; - case SENSOR_TAS5110: - sn9c10x = initTas5110; - reg17_19[0] = 0x60; - reg17_19[1] = (mode << 4) | 0x86; - reg17_19[2] = 0x2b; /* 0xf3; */ + reg12_19[5] = mode ? 0x24 : 0x20; break; - default: -/* case SENSOR_TAS5130CXX: */ - sn9c10x = initTas5130; - reg17_19[0] = 0x60; - reg17_19[1] = (mode << 4) | COMP; - reg17_19[2] = mode ? 0x23 : 0x43; + case SENSOR_TAS5130CXX: + /* probably not mode specific at all most likely the upper + nibble of 0x19 is exposure (clock divider) just as with + the tas5110, we need someone to test this. */ + reg12_19[7] = mode ? 0x23 : 0x43; break; } + /* Disable compression when the raw bayer format has been selected */ + if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) + reg12_19[6] &= ~0x80; + + /* Vga mode emulation on SIF sensor? */ + if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) { + reg12_19[0] += 16; /* 0x12: hstart adjust */ + reg12_19[1] += 24; /* 0x13: vstart adjust */ + reg12_19[3] = 320 / 16; /* 0x15: hsize */ + reg12_19[4] = 240 / 16; /* 0x16: vsize */ + } /* reg 0x01 bit 2 video transfert on */ reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1); /* reg 0x17 SensorClk enable inv Clk 0x60 */ 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) { - case SENSOR_HV7131R: - i2c_w_vector(gspca_dev, hv7131_sensor_init, - sizeof hv7131_sensor_init); - break; - case SENSOR_OV6650: - i2c_w_vector(gspca_dev, ov6650_sensor_init, - sizeof ov6650_sensor_init); - break; - case SENSOR_OV7630: - i2c_w_vector(gspca_dev, ov7630_sensor_init, - sizeof ov7630_sensor_init); - 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); - break; - case SENSOR_PAS202: - i2c_w_vector(gspca_dev, pas202_sensor_init, - sizeof pas202_sensor_init); - break; - case SENSOR_TAS5110: - i2c_w_vector(gspca_dev, tas5110_sensor_init, - sizeof tas5110_sensor_init); - break; - default: -/* case SENSOR_TAS5130CXX: */ - i2c_w_vector(gspca_dev, tas5130_sensor_init, - sizeof tas5130_sensor_init); - break; - } + reg_w(gspca_dev, 0x01, sn9c10x, l); + + /* Init the sensor */ + i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init, + sensor_data[sd->sensor].sensor_init_size); + if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge]) + i2c_w_vector(gspca_dev, + sensor_data[sd->sensor].sensor_bridge_init[sd->bridge], + sensor_data[sd->sensor].sensor_bridge_init_size[ + sd->bridge]); + /* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */ - reg_w(gspca_dev, 0x15, &sn9c10x[0x15 - 1], 2); + reg_w(gspca_dev, 0x15, ®12_19[3], 2); /* compression register */ - reg_w(gspca_dev, 0x18, ®17_19[1], 1); + reg_w(gspca_dev, 0x18, ®12_19[6], 1); /* H_start */ - reg_w(gspca_dev, 0x12, &sn9c10x[0x12 - 1], 1); + reg_w(gspca_dev, 0x12, ®12_19[0], 1); /* V_START */ - reg_w(gspca_dev, 0x13, &sn9c10x[0x13 - 1], 1); + reg_w(gspca_dev, 0x13, ®12_19[1], 1); /* reset 0x17 SensorClk enable inv Clk 0x60 */ /*fixme: ov7630 [17]=68 8f (+20 if 102)*/ - reg_w(gspca_dev, 0x17, ®17_19[0], 1); + reg_w(gspca_dev, 0x17, ®12_19[5], 1); /*MCKSIZE ->3 */ /*fixme: not ov7630*/ - reg_w(gspca_dev, 0x19, ®17_19[2], 1); + reg_w(gspca_dev, 0x19, ®12_19[7], 1); /* AE_STRX AE_STRY AE_ENDX AE_ENDY */ reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4); /* Enable video transfert */ reg_w(gspca_dev, 0x01, &sn9c10x[0], 1); /* Compression */ - reg_w(gspca_dev, 0x18, ®17_19[1], 2); + reg_w(gspca_dev, 0x18, ®12_19[6], 2); msleep(20); sd->reg11 = -1; @@ -990,18 +1010,7 @@ static void sd_start(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev) { - __u8 ByteSend; - - ByteSend = 0x09; /* 0X00 */ - reg_w(gspca_dev, 0x01, &ByteSend, 1); -} - -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ + sd_init(gspca_dev); } static void sd_pkt_scan(struct gspca_dev *gspca_dev, @@ -1011,6 +1020,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, { int i; struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam = &gspca_dev->cam; /* frames start with: * ff ff 00 c4 c4 96 synchro @@ -1031,20 +1041,31 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, && data[5 + i] == 0x96) { /* start of frame */ int lum = -1; int pkt_type = LAST_PACKET; + int fr_h_sz = (sd->bridge == BRIDGE_103) ? + 18 : 12; - if (len - i < sd->fr_h_sz) { + if (len - i < fr_h_sz) { PDEBUG(D_STREAM, "packet too short to" " get avg brightness"); - } else if (sd->fr_h_sz == 12) { - lum = data[i + 8] + (data[i + 9] << 8); - } else { + } else if (sd->bridge == BRIDGE_103) { lum = data[i + 9] + (data[i + 10] << 8); + } else { + lum = data[i + 8] + (data[i + 9] << 8); } - if (lum == 0) { + /* When exposure changes midway a frame we + get a lum of 0 in this case drop 2 frames + as the frames directly after an exposure + change have an unstable image. Sometimes lum + *really* is 0 (cam used in low light with + low exposure setting), so do not drop frames + if the previous lum was 0 too. */ + if (lum == 0 && sd->prev_avg_lum != 0) { lum = -1; sd->frames_to_drop = 2; - } + sd->prev_avg_lum = 0; + } else + sd->prev_avg_lum = lum; atomic_set(&sd->avg_lum, lum); if (sd->frames_to_drop) { @@ -1054,14 +1075,25 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, frame = gspca_frame_add(gspca_dev, pkt_type, frame, data, 0); - data += i + sd->fr_h_sz; - len -= i + sd->fr_h_sz; + data += i + fr_h_sz; + len -= i + fr_h_sz; gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); return; } } } + + if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) { + /* In raw mode we sometimes get some garbage after the frame + ignore this */ + int used = frame->data_end - frame->data; + int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage; + + if (used + len > size) + len = size - used; + } + gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } @@ -1195,58 +1227,45 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, + .dq_callback = do_autogain, }; /* -- module initialisation -- */ -#define SFCI(sensor, flags, nctrls, i2c_addr) \ - .driver_info = (SENSOR_ ## sensor << 24) \ - | ((flags) << 16) \ - | ((nctrls) << 8) \ - | (i2c_addr) +#define SB(sensor, bridge) \ + .driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge + + static __devinitdata struct usb_device_id device_table[] = { -#ifndef CONFIG_USB_SN9C102 - {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)}, + {USB_DEVICE(0x0c45, 0x6001), SB(TAS5110, 102)}, /* TAS5110C1B */ + {USB_DEVICE(0x0c45, 0x6005), SB(TAS5110, 101)}, /* TAS5110C1B */ +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x6007), SB(TAS5110, 101)}, /* TAS5110D */ + {USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)}, + {USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)}, +#endif + {USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)}, + {USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)}, + {USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)}, + {USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)}, + {USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)}, + {USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)}, +#endif + {USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)}, #endif - {USB_DEVICE(0x0c45, 0x6011), /* SN9C101 - SN9C101G */ - SFCI(OV6650, F_GAIN|F_AUTO|F_SIF, 5, 0x60)}, -#ifndef CONFIG_USB_SN9C102 - {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)}, + {USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE + {USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)}, #endif + {USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index 217a31a0e..e95613b12 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -116,6 +116,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setcolors, .get = sd_getcolors, }, +#define AUTOGAIN_IDX 3 { { .id = V4L2_CID_AUTOGAIN, @@ -459,7 +460,7 @@ static const __u8 ov7630_sensor_init[][8] = { {0xa1, 0x21, 0x2b, 0x34, 0x00, 0x00, 0x00, 0x10}, /* */ {0xa1, 0x21, 0x10, 0x83, 0x00, 0x00, 0x00, 0x10}, - {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, +/* {0xb1, 0x21, 0x01, 0x88, 0x70, 0x00, 0x00, 0x10}, */ {} }; static const __u8 ov7660_sensor_init[][8] = { @@ -628,10 +629,16 @@ static const __u8 qtable4[] = { 0x29, 0x29, 0x29, 0x29 }; -/* read <len> bytes (len < sizeof gspca_dev->usb_buf) to gspca_dev->usb_buf */ +/* read <len> bytes to gspca_dev->usb_buf */ static void reg_r(struct gspca_dev *gspca_dev, __u16 value, int len) { +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_r: buffer overflow"); + return; + } +#endif usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0), 0, @@ -664,29 +671,20 @@ static void reg_w(struct gspca_dev *gspca_dev, { PDEBUG(D_USBO, "reg_w [%02x] = %02x %02x ..", value, buffer[0], buffer[1]); - if (len <= sizeof gspca_dev->usb_buf) { - memcpy(gspca_dev->usb_buf, buffer, len); - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, 0, - gspca_dev->usb_buf, len, - 500); - } else { - __u8 *tmpbuf; - - tmpbuf = kmalloc(len, GFP_KERNEL); - memcpy(tmpbuf, buffer, len); - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0x08, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, - value, 0, - tmpbuf, len, - 500); - kfree(tmpbuf); +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_w: buffer overflow"); + return; } +#endif + memcpy(gspca_dev->usb_buf, buffer, len); + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0x08, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, + value, 0, + gspca_dev->usb_buf, len, + 500); } /* I2C write 1 byte */ @@ -832,12 +830,13 @@ static int configure_gpio(struct gspca_dev *gspca_dev, reg_w1(gspca_dev, 0x17, 0xae); reg_w1(gspca_dev, 0x01, 0x42); break; -#if 0 +#if 1 /*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); + reg_w1(gspca_dev, 0x01, 0x40); break; #endif default: @@ -966,11 +965,19 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->autogain = AUTOGAIN_DEF; sd->ag_cnt = -1; + switch (sd->sensor) { + case SENSOR_OV7630: + case SENSOR_OV7648: + case SENSOR_OV7660: + gspca_dev->ctrl_dis = (1 << AUTOGAIN_IDX); + break; + } + return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; /* const __u8 *sn9c1xx; */ @@ -1102,7 +1109,7 @@ static void setbrightcont(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; unsigned val; - __u8 reg84_full[13]; + __u8 reg84_full[0x15]; memset(reg84_full, 0, sizeof reg84_full); val = sd->contrast * 0x20 / CONTRAST_MAX + 0x10; /* 10..30 */ @@ -1114,7 +1121,7 @@ static void setbrightcont(struct gspca_dev *gspca_dev) / BRIGHTNESS_MAX; else val = 0; - reg84_full[10] = val; /* 00..1f */ + reg84_full[0x12] = val; /* 00..1f */ reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full); } @@ -1185,16 +1192,12 @@ 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; - } + if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX)) + return; + if (sd->autogain) + sd->ag_cnt = AG_CNT_START; + else + sd->ag_cnt = -1; } /* -- start the camera -- */ @@ -1214,7 +1217,6 @@ static void sd_start(struct gspca_dev *gspca_dev) sn9c1xx = sn_tb[(int) sd->sensor]; configure_gpio(gspca_dev, sn9c1xx); -/* 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]); @@ -1350,7 +1352,6 @@ static void sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x18, reg18); reg_w1(gspca_dev, 0x17, reg17); - reg_w1(gspca_dev, 0x01, reg1); switch (sd->sensor) { case SENSOR_HV7131R: case SENSOR_MI0360: @@ -1364,6 +1365,7 @@ static void sd_start(struct gspca_dev *gspca_dev) break; } setautogain(gspca_dev); + reg_w1(gspca_dev, 0x01, reg1); } static void sd_stopN(struct gspca_dev *gspca_dev) @@ -1403,14 +1405,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0xf1, 0x00); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void do_autogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -1598,11 +1592,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, }; @@ -1613,7 +1605,7 @@ static const struct sd_desc sd_desc = { | (SENSOR_ ## sensor << 8) \ | (i2c_addr) static const __devinitdata struct usb_device_id device_table[] = { -#ifndef CONFIG_USB_SN9C102 +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0458, 0x7025), BSI(SN9C120, MI0360, 0x5d)}, {USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)}, {USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)}, @@ -1646,9 +1638,11 @@ static const __devinitdata struct usb_device_id device_table[] = { {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 +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE {USB_DEVICE(0x0c45, 0x6130), BSI(SN9C120, MI0360, 0x5d)}, +#endif {USB_DEVICE(0x0c45, 0x6138), BSI(SN9C120, MO4000, 0x21)}, +#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE /* {USB_DEVICE(0x0c45, 0x613a), BSI(SN9C120, OV7648, 0x??)}, */ {USB_DEVICE(0x0c45, 0x613b), BSI(SN9C120, OV7660, 0x21)}, {USB_DEVICE(0x0c45, 0x613c), BSI(SN9C120, HV7131R, 0x11)}, diff --git a/linux/drivers/media/video/gspca/spca500.c b/linux/drivers/media/video/gspca/spca500.c index 2aff5af9a..c33bfe48c 100644 --- a/linux/drivers/media/video/gspca/spca500.c +++ b/linux/drivers/media/video/gspca/spca500.c @@ -662,8 +662,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -897,14 +897,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) gspca_dev->usb_buf[0]); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -1068,11 +1060,9 @@ static struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; diff --git a/linux/drivers/media/video/gspca/spca501.c b/linux/drivers/media/video/gspca/spca501.c index df657cb9d..49e512cac 100644 --- a/linux/drivers/media/video/gspca/spca501.c +++ b/linux/drivers/media/video/gspca/spca501.c @@ -1964,8 +1964,8 @@ error: return -EINVAL; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -2034,11 +2034,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_stop0(struct gspca_dev *gspca_dev) { -} - -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ reg_write(gspca_dev->dev, SPCA501_REG_CTLRL, 0x05, 0x00); } @@ -2131,11 +2126,10 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; diff --git a/linux/drivers/media/video/gspca/spca505.c b/linux/drivers/media/video/gspca/spca505.c index 440e6853c..e33666df4 100644 --- a/linux/drivers/media/video/gspca/spca505.c +++ b/linux/drivers/media/video/gspca/spca505.c @@ -724,8 +724,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int ret; @@ -812,11 +812,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) static void sd_stop0(struct gspca_dev *gspca_dev) { -} - -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ /* This maybe reset or power control */ reg_write(gspca_dev->dev, 0x03, 0x03, 0x20); reg_write(gspca_dev->dev, 0x03, 0x01, 0x0); @@ -894,11 +889,10 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; diff --git a/linux/drivers/media/video/gspca/spca506.c b/linux/drivers/media/video/gspca/spca506.c index ae772488c..195dce96e 100644 --- a/linux/drivers/media/video/gspca/spca506.c +++ b/linux/drivers/media/video/gspca/spca506.c @@ -313,8 +313,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct usb_device *dev = gspca_dev->dev; @@ -560,14 +560,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w(dev, 0x03, 0x00, 0x0003); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -740,11 +732,9 @@ static struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; diff --git a/linux/drivers/media/video/gspca/spca508.c b/linux/drivers/media/video/gspca/spca508.c index 585468863..5e3f66ae2 100644 --- a/linux/drivers/media/video/gspca/spca508.c +++ b/linux/drivers/media/video/gspca/spca508.c @@ -1559,8 +1559,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; /* success */ } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { /* write_vector(gspca_dev, spca508_open_data); */ return 0; @@ -1592,15 +1592,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_write(gspca_dev->dev, 0x8112, 0x20); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -1671,11 +1662,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c index d686b6bd7..b1329a149 100644 --- a/linux/drivers/media/video/gspca/spca561.c +++ b/linux/drivers/media/video/gspca/spca561.c @@ -38,9 +38,9 @@ struct sd { #define CONTRAST_MAX 0x3fff __u16 exposure; /* rev12a only */ -#define EXPOSURE_MIN 0 +#define EXPOSURE_MIN 1 #define EXPOSURE_DEF 200 -#define EXPOSURE_MAX 762 +#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */ __u8 brightness; /* rev72a only */ #define BRIGHTNESS_MIN 0 @@ -73,7 +73,7 @@ struct sd { #define AG_CNT_START 13 }; -static struct v4l2_pix_format sif_mode[] = { +static struct v4l2_pix_format sif_012a_mode[] = { {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120, @@ -96,6 +96,29 @@ static struct v4l2_pix_format sif_mode[] = { .priv = 0}, }; +static struct v4l2_pix_format sif_072a_mode[] = { + {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 160, + .sizeimage = 160 * 120, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 3}, + {176, 144, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 176, + .sizeimage = 176 * 144, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 2}, + {320, 240, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 320, + .sizeimage = 320 * 240, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1}, + {352, 288, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, + .bytesperline = 352, + .sizeimage = 352 * 288, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0}, +}; + /* * Initialization data * I'm not very sure how to split initialization from open data @@ -200,11 +223,11 @@ static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) 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--) { + do { reg_r(gspca_dev, 0x8803, 1); if (!gspca_dev->usb_buf) break; - } + } while (--retry); if (retry == 0) return -1; reg_r(gspca_dev, 0x8800, 1); @@ -560,10 +583,15 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; cam->epaddr = 0x01; gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */ - cam->cam_mode = sif_mode; - cam->nmodes = ARRAY_SIZE(sif_mode); sd->chip_revision = id->driver_info; + if (sd->chip_revision == Rev012A) { + cam->cam_mode = sif_012a_mode; + cam->nmodes = ARRAY_SIZE(sif_012a_mode); + } else { + cam->cam_mode = sif_072a_mode; + cam->nmodes = ARRAY_SIZE(sif_072a_mode); + } sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; sd->white = WHITE_DEF; @@ -574,14 +602,14 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open_12a(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init_12a(struct gspca_dev *gspca_dev) { PDEBUG(D_STREAM, "Chip revision: 012a"); init_161rev12A(gspca_dev); return 0; } -static int sd_open_72a(struct gspca_dev *gspca_dev) +static int sd_init_72a(struct gspca_dev *gspca_dev) { PDEBUG(D_STREAM, "Chip revision: 072a"); write_vector(gspca_dev, spca561_init_data); @@ -634,9 +662,31 @@ static void setexposure(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; int expo; + int clock_divider; __u8 data[2]; - expo = sd->exposure + 0x20a8; /* from test */ + /* Register 0x8309 controls exposure for the spca561, + the basic exposure setting goes from 1-2047, where 1 is completely + dark and 2047 is very bright. It not only influences exposure but + also the framerate (to allow for longer exposure) from 1 - 300 it + only raises the exposure time then from 300 - 600 it halves the + framerate to be able to further raise the exposure time and for every + 300 more it halves the framerate again. This allows for a maximum + exposure time of circa 0.2 - 0.25 seconds (30 / (2000/3000) fps). + Sometimes this is not enough, the 1-2047 uses bits 0-10, bits 11-12 + configure a divider for the base framerate which us used at the + exposure setting of 1-300. These bits configure the base framerate + according to the following formula: fps = 60 / (value + 2) */ + if (sd->exposure < 2048) { + expo = sd->exposure; + clock_divider = 0; + } else { + /* Add 900 to make the 0 setting of the second part of the + exposure equal to the 2047 setting of the first part. */ + expo = (sd->exposure - 2048) + 900; + clock_divider = 3; + } + expo |= clock_divider << 11; data[0] = expo; data[1] = expo >> 8; reg_w_buf(gspca_dev, 0x8309, data, 2); @@ -666,23 +716,11 @@ static void setautogain(struct gspca_dev *gspca_dev) static void sd_start_12a(struct gspca_dev *gspca_dev) { struct usb_device *dev = gspca_dev->dev; - int Clck; + int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */ __u8 Reg8307[] = { 0xaa, 0x00 }; int mode; mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; - 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); @@ -700,6 +738,7 @@ static void sd_start_12a(struct gspca_dev *gspca_dev) setcontrast(gspca_dev); setwhite(gspca_dev); setautogain(gspca_dev); + setexposure(gspca_dev); } static void sd_start_72a(struct gspca_dev *gspca_dev) { @@ -747,12 +786,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev) reg_w_val(gspca_dev->dev, 0x8118, 0x29); reg_w_val(gspca_dev->dev, 0x8114, 0x08); } -} - -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ - reg_w_val(gspca_dev->dev, 0x8114, 0); +/* reg_w_val(gspca_dev->dev, 0x8114, 0); */ } static void do_autogain(struct gspca_dev *gspca_dev) @@ -840,6 +874,8 @@ 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, @@ -852,8 +888,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, frame, data, len); } else { /* raw bayer (with a header, which we skip) */ - data += 20; - len -= 20; + if (sd->chip_revision == Rev012A) { + data += 20; + len -= 20; + } else { + data += 16; + len -= 16; + } gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); } @@ -1135,11 +1176,10 @@ static const struct sd_desc sd_desc_12a = { .ctrls = sd_ctrls_12a, .nctrls = ARRAY_SIZE(sd_ctrls_12a), .config = sd_config, - .open = sd_open_12a, + .init = sd_init_12a, .start = sd_start_12a, .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, /* .dq_callback = do_autogain, * fixme */ }; @@ -1148,11 +1188,10 @@ static const struct sd_desc sd_desc_72a = { .ctrls = sd_ctrls_72a, .nctrls = ARRAY_SIZE(sd_ctrls_72a), .config = sd_config, - .open = sd_open_72a, + .init = sd_init_72a, .start = sd_start_72a, .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, }; diff --git a/linux/drivers/media/video/gspca/stk014.c b/linux/drivers/media/video/gspca/stk014.c index 387a8cf2b..2f2de429e 100644 --- a/linux/drivers/media/video/gspca/stk014.c +++ b/linux/drivers/media/video/gspca/stk014.c @@ -306,8 +306,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { int ret; @@ -398,14 +398,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) PDEBUG(D_STREAM, "camera stopped"); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -535,11 +527,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, }; diff --git a/linux/drivers/media/video/gspca/sunplus.c b/linux/drivers/media/video/gspca/sunplus.c index e1a7e53ba..e8e5c47ba 100644 --- a/linux/drivers/media/video/gspca/sunplus.c +++ b/linux/drivers/media/video/gspca/sunplus.c @@ -480,31 +480,47 @@ static const __u8 qtable_spca504_default[2][64] = { 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e} }; -static void reg_r(struct usb_device *dev, - __u16 req, - __u16 index, - __u8 *buffer, __u16 length) +/* read <len> bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 req, + __u16 index, + __u16 len) { - usb_control_msg(dev, - usb_rcvctrlpipe(dev, 0), +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_r: buffer overflow"); + return; + } +#endif + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, /* value */ - index, buffer, length, + index, + len ? gspca_dev->usb_buf : NULL, len, 500); } -static void reg_w(struct usb_device *dev, - __u16 req, - __u16 value, - __u16 index, - __u8 *buffer, __u16 length) +/* write <len> bytes from gspca_dev->usb_buf */ +static void reg_w(struct gspca_dev *gspca_dev, + __u16 req, + __u16 value, + __u16 index, + __u16 len) { - usb_control_msg(dev, - usb_sndctrlpipe(dev, 0), +#ifdef GSPCA_DEBUG + if (len > USB_BUF_SZ) { + err("reg_w: buffer overflow"); + return; + } +#endif + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, buffer, length, + value, index, + len ? gspca_dev->usb_buf : NULL, len, 500); } @@ -665,7 +681,7 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev) int count = 10; while (--count > 0) { - reg_r(gspca_dev->dev, 0x21, 0, gspca_dev->usb_buf, 1); + reg_r(gspca_dev, 0x21, 0, 1); if ((gspca_dev->usb_buf[0] & 0x01) == 0) break; msleep(10); @@ -675,15 +691,14 @@ static int spca504B_PollingDataReady(struct gspca_dev *gspca_dev) static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) { - struct usb_device *dev = gspca_dev->dev; int count = 50; while (--count > 0) { - reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1); + reg_r(gspca_dev, 0x21, 1, 1); if (gspca_dev->usb_buf[0] != 0) { gspca_dev->usb_buf[0] = 0; - reg_w(dev, 0x21, 0, 1, gspca_dev->usb_buf, 1); - reg_r(dev, 0x21, 1, gspca_dev->usb_buf, 1); + reg_w(gspca_dev, 0x21, 0, 1, 1); + reg_r(gspca_dev, 0x21, 1, 1); spca504B_PollingDataReady(gspca_dev); break; } @@ -693,16 +708,14 @@ static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev) static void spca50x_GetFirmware(struct gspca_dev *gspca_dev) { - struct usb_device *dev = gspca_dev->dev; __u8 *data; - data = kmalloc(64, GFP_KERNEL); - reg_r(dev, 0x20, 0, data, 5); + data = gspca_dev->usb_buf; + reg_r(gspca_dev, 0x20, 0, 5); PDEBUG(D_STREAM, "FirmWare : %d %d %d %d %d ", data[0], data[1], data[2], data[3], data[4]); - reg_r(dev, 0x23, 0, data, 64); - reg_r(dev, 0x23, 1, data, 64); - kfree(data); + reg_r(gspca_dev, 0x23, 0, 64); + reg_r(gspca_dev, 0x23, 1, 64); } static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) @@ -717,21 +730,21 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) Type = 0; switch (sd->bridge) { case BRIDGE_SPCA533: - reg_w(dev, 0x31, 0, 0, NULL, 0); + reg_w(gspca_dev, 0x31, 0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); rc = spca504B_PollingDataReady(gspca_dev); spca50x_GetFirmware(gspca_dev); gspca_dev->usb_buf[0] = 2; /* type */ - reg_w(dev, 0x24, 0, 8, gspca_dev->usb_buf, 1); - reg_r(dev, 0x24, 8, gspca_dev->usb_buf, 1); + reg_w(gspca_dev, 0x24, 0, 8, 1); + reg_r(gspca_dev, 0x24, 8, 1); gspca_dev->usb_buf[0] = Size; - reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1); - reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */ + reg_w(gspca_dev, 0x25, 0, 4, 1); + reg_r(gspca_dev, 0x25, 4, 1); /* size */ rc = spca504B_PollingDataReady(gspca_dev); /* Init the cam width height with some values get on init ? */ - reg_w(dev, 0x31, 0, 4, NULL, 0); + reg_w(gspca_dev, 0x31, 0, 4, 0); spca504B_WaitCmdStatus(gspca_dev); rc = spca504B_PollingDataReady(gspca_dev); break; @@ -739,12 +752,12 @@ static void spca504B_SetSizeType(struct gspca_dev *gspca_dev) /* case BRIDGE_SPCA504B: */ /* case BRIDGE_SPCA536: */ gspca_dev->usb_buf[0] = Size; - reg_w(dev, 0x25, 0, 4, gspca_dev->usb_buf, 1); - reg_r(dev, 0x25, 4, gspca_dev->usb_buf, 1); /* size */ + reg_w(gspca_dev, 0x25, 0, 4, 1); + reg_r(gspca_dev, 0x25, 4, 1); /* size */ Type = 6; gspca_dev->usb_buf[0] = Type; - reg_w(dev, 0x27, 0, 0, gspca_dev->usb_buf, 1); - reg_r(dev, 0x27, 0, gspca_dev->usb_buf, 1); /* type */ + reg_w(gspca_dev, 0x27, 0, 0, 1); + reg_r(gspca_dev, 0x27, 0, 1); /* type */ rc = spca504B_PollingDataReady(gspca_dev); break; case BRIDGE_SPCA504: @@ -783,18 +796,15 @@ static void spca504_wait_status(struct gspca_dev *gspca_dev) static void spca504B_setQtable(struct gspca_dev *gspca_dev) { - struct usb_device *dev = gspca_dev->dev; - gspca_dev->usb_buf[0] = 3; - reg_w(dev, 0x26, 0, 0, gspca_dev->usb_buf, 1); - reg_r(dev, 0x26, 0, gspca_dev->usb_buf, 1); + reg_w(gspca_dev, 0x26, 0, 0, 1); + reg_r(gspca_dev, 0x26, 0, 1); spca504B_PollingDataReady(gspca_dev); } static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; int pollreg = 1; switch (sd->bridge) { @@ -805,20 +815,20 @@ static void sp5xx_initContBrigHueRegisters(struct gspca_dev *gspca_dev) default: /* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA504B: */ - reg_w(dev, 0, 0, 0x21a7, NULL, 0); /* brightness */ - reg_w(dev, 0, 0x20, 0x21a8, NULL, 0); /* contrast */ - reg_w(dev, 0, 0, 0x21ad, NULL, 0); /* hue */ - reg_w(dev, 0, 1, 0x21ac, NULL, 0); /* sat/hue */ - reg_w(dev, 0, 0x20, 0x21ae, NULL, 0); /* saturation */ - reg_w(dev, 0, 0, 0x21a3, NULL, 0); /* gamma */ + reg_w(gspca_dev, 0, 0, 0x21a7, 0); /* brightness */ + reg_w(gspca_dev, 0, 0x20, 0x21a8, 0); /* contrast */ + reg_w(gspca_dev, 0, 0, 0x21ad, 0); /* hue */ + reg_w(gspca_dev, 0, 1, 0x21ac, 0); /* sat/hue */ + reg_w(gspca_dev, 0, 0x20, 0x21ae, 0); /* saturation */ + reg_w(gspca_dev, 0, 0, 0x21a3, 0); /* gamma */ break; case BRIDGE_SPCA536: - reg_w(dev, 0, 0, 0x20f0, NULL, 0); - reg_w(dev, 0, 0x21, 0x20f1, NULL, 0); - reg_w(dev, 0, 0x40, 0x20f5, NULL, 0); - reg_w(dev, 0, 1, 0x20f4, NULL, 0); - reg_w(dev, 0, 0x40, 0x20f6, NULL, 0); - reg_w(dev, 0, 0, 0x2089, NULL, 0); + reg_w(gspca_dev, 0, 0, 0x20f0, 0); + reg_w(gspca_dev, 0, 0x21, 0x20f1, 0); + reg_w(gspca_dev, 0, 0x40, 0x20f5, 0); + reg_w(gspca_dev, 0, 1, 0x20f4, 0); + reg_w(gspca_dev, 0, 0x40, 0x20f6, 0); + reg_w(gspca_dev, 0, 0, 0x2089, 0); break; } if (pollreg) @@ -830,7 +840,6 @@ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { struct sd *sd = (struct sd *) gspca_dev; - struct usb_device *dev = gspca_dev->dev; struct cam *cam; cam = &gspca_dev->cam; @@ -842,7 +851,7 @@ static int sd_config(struct gspca_dev *gspca_dev, 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); + reg_r(gspca_dev, 0x20, 0, 1); switch (gspca_dev->usb_buf[0]) { case 1: break; /* (right bridge/subtype) */ @@ -879,8 +888,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; @@ -891,12 +900,12 @@ static int sd_open(struct gspca_dev *gspca_dev) switch (sd->bridge) { case BRIDGE_SPCA504B: - reg_w(dev, 0x1d, 0, 0, NULL, 0); - reg_w(dev, 0, 1, 0x2306, NULL, 0); - reg_w(dev, 0, 0, 0x0d04, NULL, 0); - reg_w(dev, 0, 0, 0x2000, NULL, 0); - reg_w(dev, 0, 0x13, 0x2301, NULL, 0); - reg_w(dev, 0, 0, 0x2306, NULL, 0); + reg_w(gspca_dev, 0x1d, 0, 0, 0); + reg_w(gspca_dev, 0, 1, 0x2306, 0); + reg_w(gspca_dev, 0, 0, 0x0d04, 0); + reg_w(gspca_dev, 0, 0, 0x2000, 0); + reg_w(gspca_dev, 0, 0x13, 0x2301, 0); + reg_w(gspca_dev, 0, 0, 0x2306, 0); /* fall thru */ case BRIDGE_SPCA533: rc = spca504B_PollingDataReady(gspca_dev); @@ -904,12 +913,12 @@ static int sd_open(struct gspca_dev *gspca_dev) break; case BRIDGE_SPCA536: spca50x_GetFirmware(gspca_dev); - reg_r(dev, 0x00, 0x5002, gspca_dev->usb_buf, 1); + reg_r(gspca_dev, 0x00, 0x5002, 1); gspca_dev->usb_buf[0] = 0; - reg_w(dev, 0x24, 0, 0, gspca_dev->usb_buf, 1); - reg_r(dev, 0x24, 0, gspca_dev->usb_buf, 1); + reg_w(gspca_dev, 0x24, 0, 0, 1); + reg_r(gspca_dev, 0x24, 0, 1); rc = spca504B_PollingDataReady(gspca_dev); - reg_w(dev, 0x34, 0, 0, NULL, 0); + reg_w(gspca_dev, 0x34, 0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); break; case BRIDGE_SPCA504C: /* pccam600 */ @@ -1002,12 +1011,12 @@ static void sd_start(struct gspca_dev *gspca_dev) /* case BRIDGE_SPCA536: */ if (sd->subtype == MegapixV4 || sd->subtype == LogitechClickSmart820) { - reg_w(dev, 0xf0, 0, 0, NULL, 0); + reg_w(gspca_dev, 0xf0, 0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); - reg_r(dev, 0xf0, 4, NULL, 0); + reg_r(gspca_dev, 0xf0, 4, 0); spca504B_WaitCmdStatus(gspca_dev); } else { - reg_w(dev, 0x31, 0, 4, NULL, 0); + reg_w(gspca_dev, 0x31, 0, 4, 0); spca504B_WaitCmdStatus(gspca_dev); rc = spca504B_PollingDataReady(gspca_dev); } @@ -1076,7 +1085,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev) /* case BRIDGE_SPCA533: */ /* case BRIDGE_SPCA536: */ /* case BRIDGE_SPCA504B: */ - reg_w(dev, 0x31, 0, 0, NULL, 0); + reg_w(gspca_dev, 0x31, 0, 0, 0); spca504B_WaitCmdStatus(gspca_dev); spca504B_PollingDataReady(gspca_dev); break; @@ -1100,14 +1109,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) } } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -1400,11 +1401,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; diff --git a/linux/drivers/media/video/gspca/t613.c b/linux/drivers/media/video/gspca/t613.c index 27bff51a0..c7673661a 100644 --- a/linux/drivers/media/video/gspca/t613.c +++ b/linux/drivers/media/video/gspca/t613.c @@ -391,7 +391,7 @@ static void reg_w(struct gspca_dev *gspca_dev, NULL, 0, 500); return; } - if (len <= sizeof gspca_dev->usb_buf) { + if (len <= USB_BUF_SZ) { memcpy(gspca_dev->usb_buf, buffer, len); usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), @@ -563,6 +563,13 @@ static int init_default_parameters(struct gspca_dev *gspca_dev) return 0; } +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) +{ + init_default_parameters(gspca_dev); + return 0; +} + static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -916,18 +923,6 @@ static void sd_start(struct gspca_dev *gspca_dev) #endif } -static void sd_stopN(struct gspca_dev *gspca_dev) -{ -} - -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -995,24 +990,14 @@ static int sd_querymenu(struct gspca_dev *gspca_dev, return -EINVAL; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) -{ - init_default_parameters(gspca_dev); - return 0; -} - /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, - .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, }; diff --git a/linux/drivers/media/video/gspca/tv8532.c b/linux/drivers/media/video/gspca/tv8532.c index c55dbe8ac..01de48d4e 100644 --- a/linux/drivers/media/video/gspca/tv8532.c +++ b/linux/drivers/media/video/gspca/tv8532.c @@ -331,8 +331,8 @@ static void tv_8532_PollReg(struct gspca_dev *gspca_dev) } } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { reg_w_1(gspca_dev, TV8532_AD_SLOPE, 0x32); reg_w_1(gspca_dev, TV8532_AD_BITCTRL, 0x00); @@ -450,14 +450,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w_1(gspca_dev, TV8532_GPIO_OE, 0x0b); } -static void sd_stop0(struct gspca_dev *gspca_dev) -{ -} - -static void sd_close(struct gspca_dev *gspca_dev) -{ -} - static void tv8532_preprocess(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -620,11 +612,9 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, }; diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c index f37c63d6d..cfb66c257 100644 --- a/linux/drivers/media/video/gspca/vc032x.c +++ b/linux/drivers/media/video/gspca/vc032x.c @@ -69,6 +69,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setautogain, .get = sd_getautogain, }, +#define LIGHTFREQ_IDX 1 { { .id = V4L2_CID_POWER_LINE_FREQUENCY, @@ -79,7 +80,6 @@ static struct ctrl sd_ctrls[] = { .step = 1, #define FREQ_DEF 1 .default_value = FREQ_DEF, - .default_value = 1, }, .set = sd_setfreq, .get = sd_getfreq, @@ -87,12 +87,12 @@ static struct ctrl sd_ctrls[] = { }; static struct v4l2_pix_format vc0321_mode[] = { - {320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, + {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 2, .colorspace = V4L2_COLORSPACE_SRGB, .priv = 1}, - {640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE, + {640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, .bytesperline = 640, .sizeimage = 640 * 480 * 2, .colorspace = V4L2_COLORSPACE_SRGB, @@ -1643,6 +1643,8 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->qindex = 7; sd->autogain = AUTOGAIN_DEF; sd->lightfreq = FREQ_DEF; + if (sd->sensor != SENSOR_OV7670) + gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX); if (sd->bridge == BRIDGE_VC0321) { reg_r(gspca_dev, 0x8a, 0, 3); @@ -1654,8 +1656,8 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and time */ +static int sd_init(struct gspca_dev *gspca_dev) { return 0; } @@ -1834,19 +1836,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev) reg_w(dev, 0x89, 0xffff, 0xffff); } -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ -/* struct usb_device *dev = gspca_dev->dev; - __u8 buffread; - - reg_w(dev, 0x89, 0xffff, 0xffff); - reg_w(dev, 0xa0, 0x01, 0xb301); - reg_w(dev, 0xa0, 0x09, 0xb303); - reg_w(dev, 0x89, 0xffff, 0xffff); -*/ -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, /* target */ __u8 *data, /* isoc packet */ @@ -1935,11 +1924,10 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, }; diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c index a3f109ac4..782952b7a 100644 --- a/linux/drivers/media/video/gspca/zc3xx.c +++ b/linux/drivers/media/video/gspca/zc3xx.c @@ -70,10 +70,6 @@ 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); @@ -89,6 +85,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { +#define BRIGHTNESS_IDX 0 #define SD_BRIGHTNESS 0 { { @@ -145,6 +142,7 @@ static struct ctrl sd_ctrls[] = { .set = sd_setautogain, .get = sd_getautogain, }, +#define LIGHTFREQ_IDX 4 #define SD_FREQ 4 { { @@ -7024,8 +7022,7 @@ static int sd_config(struct gspca_dev *gspca_dev, /* define some sensors from the vendor/product */ sd->sharpness = 2; - sd->sensor = DRIVER_INFO_GET_SENSOR(id->driver_info); - gspca_dev->flags = DRIVER_INFO_GET_FLAGS(id->driver_info); + sd->sensor = id->driver_info; sensor = zcxx_probeSensor(gspca_dev); if (sensor >= 0) PDEBUG(D_PROBE, "probe sensor -> %02x", sensor); @@ -7160,13 +7157,27 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value; sd->sharpness = sd_ctrls[SD_SHARPNESS].qctrl.default_value; + switch (sd->sensor) { + case SENSOR_GC0305: + case SENSOR_OV7620: + case SENSOR_PO2030: + gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX); + break; + case SENSOR_HDCS2020: + case SENSOR_HV7131B: + case SENSOR_HV7131C: + case SENSOR_OV7630C: + gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX); + break; + } + /* switch the led off */ reg_w(gspca_dev->dev, 0x01, 0x0000); return 0; } -/* this function is called at open time */ -static int sd_open(struct gspca_dev *gspca_dev) +/* this function is called at probe and resume time */ +static int sd_init(struct gspca_dev *gspca_dev) { reg_w(gspca_dev->dev, 0x01, 0x0000); return 0; @@ -7327,10 +7338,6 @@ static void sd_start(struct gspca_dev *gspca_dev) } } -static void sd_stopN(struct gspca_dev *gspca_dev) -{ -} - static void sd_stop0(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -7338,18 +7345,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev) send_unknown(gspca_dev->dev, sd->sensor); } -/* this function is called at close time */ -static void sd_close(struct gspca_dev *gspca_dev) -{ -#if 0 /* test */ - struct usb_device *dev = gspca_dev->dev; - - reg_r(gspca_dev, 0x0180); - reg_w(dev, 0x00, 0x0180); - reg_w(dev, 0x01, 0x0000); -#endif -} - static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, __u8 *data, @@ -7509,37 +7504,30 @@ static const struct sd_desc sd_desc = { .ctrls = sd_ctrls, .nctrls = sizeof sd_ctrls / sizeof sd_ctrls[0], .config = sd_config, - .open = sd_open, + .init = sd_init, .start = sd_start, - .stopN = sd_stopN, .stop0 = sd_stop0, - .close = sd_close, .pkt_scan = sd_pkt_scan, .querymenu = sd_querymenu, }; static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x041e)}, -#ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x041e, 0x4017)}, - {USB_DEVICE(0x041e, 0x401c), DRIVER_INFO(SENSOR_PAS106, 0)}, + {USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x041e, 0x401e)}, {USB_DEVICE(0x041e, 0x401f)}, -#endif + {USB_DEVICE(0x041e, 0x4022)}, {USB_DEVICE(0x041e, 0x4029)}, -#ifndef CONFIG_USB_ZC0301 - {USB_DEVICE(0x041e, 0x4034), DRIVER_INFO(SENSOR_PAS106, 0)}, - {USB_DEVICE(0x041e, 0x4035), DRIVER_INFO(SENSOR_PAS106, 0)}, + {USB_DEVICE(0x041e, 0x4034), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x041e, 0x4035), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x041e, 0x4036)}, {USB_DEVICE(0x041e, 0x403a)}, -#endif - {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(0x041e, 0x4051), .driver_info = SENSOR_TAS5130C_VF0250}, + {USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_TAS5130C_VF0250}, {USB_DEVICE(0x0458, 0x7007)}, {USB_DEVICE(0x0458, 0x700c)}, {USB_DEVICE(0x0458, 0x700f)}, -#endif {USB_DEVICE(0x0461, 0x0a00)}, {USB_DEVICE(0x046d, 0x08a0)}, {USB_DEVICE(0x046d, 0x08a1)}, @@ -7551,7 +7539,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x046d, 0x08aa)}, {USB_DEVICE(0x046d, 0x08ac)}, {USB_DEVICE(0x046d, 0x08ad)}, -#ifndef CONFIG_USB_ZC0301 +#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE {USB_DEVICE(0x046d, 0x08ae)}, #endif {USB_DEVICE(0x046d, 0x08af)}, @@ -7560,30 +7548,26 @@ static const __devinitdata struct usb_device_id device_table[] = { {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(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB}, + {USB_DEVICE(0x0471, 0x0325), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x0326), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x032d), .driver_info = SENSOR_PAS106}, + {USB_DEVICE(0x0471, 0x032e), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x055f, 0xc005)}, -#ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x055f, 0xd003)}, {USB_DEVICE(0x055f, 0xd004)}, -#endif {USB_DEVICE(0x0698, 0x2003)}, + {USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106}, {USB_DEVICE(0x0ac8, 0x0302)}, -#ifndef CONFIG_USB_ZC0301 {USB_DEVICE(0x0ac8, 0x301b)}, +#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE {USB_DEVICE(0x0ac8, 0x303b)}, #endif - {USB_DEVICE(0x0ac8, 0x305b), DRIVER_INFO(SENSOR_TAS5130C_VF0250, 0)}, -#ifndef CONFIG_USB_ZC0301 + {USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250}, {USB_DEVICE(0x0ac8, 0x307b)}, {USB_DEVICE(0x10fd, 0x0128)}, + {USB_DEVICE(0x10fd, 0x804d)}, {USB_DEVICE(0x10fd, 0x8050)}, -#endif {} /* end of entry */ }; #undef DVNAME diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.c b/linux/drivers/media/video/ivtv/ivtv-driver.c index 89a16bfeb..def2c5502 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.c +++ b/linux/drivers/media/video/ivtv/ivtv-driver.c @@ -655,9 +655,9 @@ done: if (itv->card == NULL) { itv->card = ivtv_get_card(IVTV_CARD_PVR_150); - IVTV_ERR("Unknown card: vendor/device: %04x/%04x\n", + IVTV_ERR("Unknown card: vendor/device: [%04x:%04x]\n", itv->dev->vendor, itv->dev->device); - IVTV_ERR(" subsystem vendor/device: %04x/%04x\n", + IVTV_ERR(" subsystem vendor/device: [%04x:%04x]\n", itv->dev->subsystem_vendor, itv->dev->subsystem_device); IVTV_ERR(" %s based\n", chipname); IVTV_ERR("Defaulting to %s card\n", itv->card->name); diff --git a/linux/drivers/media/video/ivtv/ivtv-driver.h b/linux/drivers/media/video/ivtv/ivtv-driver.h index 6e0ca223a..80673a3da 100644 --- a/linux/drivers/media/video/ivtv/ivtv-driver.h +++ b/linux/drivers/media/video/ivtv/ivtv-driver.h @@ -49,7 +49,6 @@ #include <linux/i2c-algo-bit.h> #include <linux/list.h> #include <linux/unistd.h> -#include <linux/byteorder/swab.h> #include <linux/pagemap.h> #include <linux/scatterlist.h> #include <linux/workqueue.h> diff --git a/linux/drivers/media/video/ivtv/ivtv-i2c.c b/linux/drivers/media/video/ivtv/ivtv-i2c.c index 1488bc7ce..180f541f0 100644 --- a/linux/drivers/media/video/ivtv/ivtv-i2c.c +++ b/linux/drivers/media/video/ivtv/ivtv-i2c.c @@ -64,8 +64,6 @@ #include "ivtv-gpio.h" #include "ivtv-i2c.h" -#include <media/ir-kbd-i2c.h> - /* i2c implementation for cx23415/6 chip, ivtv project. * Author: Kevin Thayer (nufan_wfk at yahoo.com) */ diff --git a/linux/drivers/media/video/ks0127.c b/linux/drivers/media/video/ks0127.c index 90451230d..b21b6f097 100644 --- a/linux/drivers/media/video/ks0127.c +++ b/linux/drivers/media/video/ks0127.c @@ -680,26 +680,27 @@ static int ks0127_command(struct i2c_client *client, case DECODER_ENABLE_OUTPUT: { + int enable; - int *iarg = arg; - int enable = (*iarg != 0); - if (enable) { - dprintk("ks0127: command " + iarg = arg; + enable = (*iarg != 0); + if (enable) { + dprintk("ks0127: command " "DECODER_ENABLE_OUTPUT on " "(%d)\n", enable); - /* All output pins on */ - ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30); - /* Obey the OEN pin */ - ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00); - } else { - dprintk("ks0127: command " + /* All output pins on */ + ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x30); + /* Obey the OEN pin */ + ks0127_and_or(ks, KS_CDEM, 0x7f, 0x00); + } else { + dprintk("ks0127: command " "DECODER_ENABLE_OUTPUT off " "(%d)\n", enable); - /* Video output pins off */ - ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00); - /* Ignore the OEN pin */ - ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80); - } + /* Video output pins off */ + ks0127_and_or(ks, KS_OFMTA, 0xcf, 0x00); + /* Ignore the OEN pin */ + ks0127_and_or(ks, KS_CDEM, 0x7f, 0x80); + } } break; diff --git a/linux/drivers/media/video/meye.c b/linux/drivers/media/video/meye.c index a0cdae0c1..535443887 100644 --- a/linux/drivers/media/video/meye.c +++ b/linux/drivers/media/video/meye.c @@ -848,21 +848,16 @@ again: static int meye_open(struct inode *inode, struct file *file) { - int i, err; + int i; - lock_kernel(); - err = video_exclusive_open(inode, file); - if (err < 0) { - unlock_kernel(); - return err; - } + if (test_and_set_bit(0, &meye.in_use)) + return -EBUSY; mchip_hic_stop(); if (mchip_dma_alloc()) { printk(KERN_ERR "meye: mchip framebuffer allocation failed\n"); - video_exclusive_release(inode, file); - unlock_kernel(); + clear_bit(0, &meye.in_use); return -ENOBUFS; } @@ -870,7 +865,6 @@ 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; } @@ -878,7 +872,7 @@ static int meye_release(struct inode *inode, struct file *file) { mchip_hic_stop(); mchip_dma_free(); - video_exclusive_release(inode, file); + clear_bit(0, &meye.in_use); return 0; } @@ -1784,6 +1778,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev, goto outnotdev; } + ret = -ENOMEM; meye.mchip_dev = pcidev; meye.video_dev = video_device_alloc(); if (!meye.video_dev) { @@ -1791,7 +1786,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev, goto outnotdev; } - ret = -ENOMEM; meye.grab_temp = vmalloc(MCHIP_NB_PAGES_MJPEG * PAGE_SIZE); if (!meye.grab_temp) { printk(KERN_ERR "meye: grab buffer allocation failed\n"); @@ -1816,6 +1810,7 @@ static int __devinit meye_probe(struct pci_dev *pcidev, memcpy(meye.video_dev, &meye_template, sizeof(meye_template)); meye.video_dev->parent = &meye.mchip_dev->dev; + ret = -EIO; if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) { printk(KERN_ERR "meye: unable to power on the camera\n"); printk(KERN_ERR "meye: did you enable the camera in " @@ -1823,7 +1818,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev, goto outsonypienable; } - ret = -EIO; if ((ret = pci_enable_device(meye.mchip_dev))) { printk(KERN_ERR "meye: pci_enable_device failed\n"); goto outenabledev; diff --git a/linux/drivers/media/video/meye.h b/linux/drivers/media/video/meye.h index 4c0c031d3..b4a589f21 100644 --- a/linux/drivers/media/video/meye.h +++ b/linux/drivers/media/video/meye.h @@ -315,6 +315,7 @@ struct meye { struct video_device *video_dev; /* video device parameters */ struct video_picture picture; /* video picture parameters */ struct meye_params params; /* additional parameters */ + unsigned long in_use; /* set to 1 if the device is in use */ #ifdef CONFIG_PM u8 pm_mchip_mode; /* old mchip mode */ #endif diff --git a/linux/drivers/media/video/mt9m111.c b/linux/drivers/media/video/mt9m111.c index e4ec7538d..ceff40edc 100644 --- a/linux/drivers/media/video/mt9m111.c +++ b/linux/drivers/media/video/mt9m111.c @@ -755,7 +755,7 @@ static int mt9m111_set_control(struct soc_camera_device *icd, return ret; } -int mt9m111_restore_state(struct soc_camera_device *icd) +static int mt9m111_restore_state(struct soc_camera_device *icd) { struct mt9m111 *mt9m111 = container_of(icd, struct mt9m111, icd); diff --git a/linux/drivers/media/video/mt9v022.c b/linux/drivers/media/video/mt9v022.c index 0320d006f..bea695a2c 100644 --- a/linux/drivers/media/video/mt9v022.c +++ b/linux/drivers/media/video/mt9v022.c @@ -25,7 +25,7 @@ static char *sensor_type; module_param(sensor_type, charp, S_IRUGO); -MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"\n"); +MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\""); /* mt9v022 selected register addresses */ #define MT9V022_CHIP_VERSION 0x00 diff --git a/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c index 974505a9e..e0fbbd3a7 100644 --- a/linux/drivers/media/video/mxb.c +++ b/linux/drivers/media/video/mxb.c @@ -931,27 +931,29 @@ static int mxb_ioctl(struct saa7146_fh *fh, unsigned int cmd, void *arg) return 0; } -static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std) +static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standard) { - struct mxb* mxb = (struct mxb*)dev->ext_priv; + struct mxb *mxb = (struct mxb *)dev->ext_priv; int zero = 0; int one = 1; - if(V4L2_STD_PAL_I == std->id ) { + if (V4L2_STD_PAL_I == standard->id) { v4l2_std_id std = V4L2_STD_PAL_I; + DEB_D(("VIDIOC_S_STD: setting mxb for PAL_I.\n")); /* set the 7146 gpio register -- I don't know what this does exactly */ saa7146_write(dev, GPIO_CTRL, 0x00404050); /* unset the 7111 gpio register -- I don't know what this does exactly */ - mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &zero); + mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &zero); mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std); } else { v4l2_std_id std = V4L2_STD_PAL_BG; + DEB_D(("VIDIOC_S_STD: setting mxb for PAL/NTSC/SECAM.\n")); /* set the 7146 gpio register -- I don't know what this does exactly */ saa7146_write(dev, GPIO_CTRL, 0x00404050); /* set the 7111 gpio register -- I don't know what this does exactly */ - mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_GPIO, &one); + mxb->saa7111a->driver->command(mxb->saa7111a, DECODER_SET_GPIO, &one); mxb->tuner->driver->command(mxb->tuner, VIDIOC_S_STD, &std); } return 0; diff --git a/linux/drivers/media/video/ov511.c b/linux/drivers/media/video/ov511.c index c693b6fb0..3f1d7a660 100644 --- a/linux/drivers/media/video/ov511.c +++ b/linux/drivers/media/video/ov511.c @@ -626,9 +626,9 @@ ov511_i2c_write_internal(struct usb_ov511 *ov, break; /* Retry until idle */ - do + do { rc = reg_r(ov, R511_I2C_CTL); - while (rc > 0 && ((rc&1) == 0)); + } while (rc > 0 && ((rc&1) == 0)); if (rc < 0) break; @@ -703,9 +703,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) return rc; /* Retry until idle */ - do - rc = reg_r(ov, R511_I2C_CTL); - while (rc > 0 && ((rc&1) == 0)); + do { + rc = reg_r(ov, R511_I2C_CTL); + } while (rc > 0 && ((rc & 1) == 0)); if (rc < 0) return rc; @@ -729,9 +729,9 @@ ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg) return rc; /* Retry until idle */ - do + do { rc = reg_r(ov, R511_I2C_CTL); - while (rc > 0 && ((rc&1) == 0)); + } while (rc > 0 && ((rc&1) == 0)); if (rc < 0) return rc; @@ -3595,7 +3595,7 @@ static int ov51x_init_isoc(struct usb_ov511 *ov) { struct urb *urb; - int fx, err, n, size; + int fx, err, n, i, size; PDEBUG(3, "*** Initializing capture ***"); @@ -3666,6 +3666,8 @@ ov51x_init_isoc(struct usb_ov511 *ov) urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL); if (!urb) { err("init isoc: usb_alloc_urb ret. NULL"); + for (i = 0; i < n; i++) + usb_free_urb(ov->sbuf[i].urb); return -ENOMEM; } ov->sbuf[n].urb = urb; @@ -5655,7 +5657,7 @@ static ssize_t show_exposure(struct device *cd, if (!ov->dev) return -ENODEV; sensor_get_exposure(ov, &exp); - return sprintf(buf, "%d\n", exp >> 8); + return sprintf(buf, "%d\n", exp); } static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL); diff --git a/linux/drivers/media/video/ovcamchip/ovcamchip_core.c b/linux/drivers/media/video/ovcamchip/ovcamchip_core.c index 065c24541..2c4acbf5a 100644 --- a/linux/drivers/media/video/ovcamchip/ovcamchip_core.c +++ b/linux/drivers/media/video/ovcamchip/ovcamchip_core.c @@ -49,12 +49,6 @@ MODULE_LICENSE("GPL"); #define GENERIC_REG_ID_LOW 0x1D /* manufacturer ID LSB */ #define GENERIC_REG_COM_I 0x29 /* misc ID bits */ -extern struct ovcamchip_ops ov6x20_ops; -extern struct ovcamchip_ops ov6x30_ops; -extern struct ovcamchip_ops ov7x10_ops; -extern struct ovcamchip_ops ov7x20_ops; -extern struct ovcamchip_ops ov76be_ops; - static char *chip_names[NUM_CC_TYPES] = { [CC_UNKNOWN] = "Unknown chip", [CC_OV76BE] = "OV76BE", diff --git a/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h b/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h index 9afa4fe47..a05650fae 100644 --- a/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h +++ b/linux/drivers/media/video/ovcamchip/ovcamchip_priv.h @@ -53,6 +53,12 @@ struct ovcamchip { int initialized; /* OVCAMCHIP_CMD_INITIALIZE was successful */ }; +extern struct ovcamchip_ops ov6x20_ops; +extern struct ovcamchip_ops ov6x30_ops; +extern struct ovcamchip_ops ov7x10_ops; +extern struct ovcamchip_ops ov7x20_ops; +extern struct ovcamchip_ops ov76be_ops; + /* --------------------------------- */ /* I2C I/O */ /* --------------------------------- */ diff --git a/linux/drivers/media/video/pms.c b/linux/drivers/media/video/pms.c index 8c51ee442..00b623e00 100644 --- a/linux/drivers/media/video/pms.c +++ b/linux/drivers/media/video/pms.c @@ -48,6 +48,7 @@ struct pms_device struct video_picture picture; int height; int width; + unsigned long in_use; struct mutex lock; }; @@ -882,10 +883,27 @@ static ssize_t pms_read(struct file *file, char __user *buf, return len; } +static int pms_exclusive_open(struct inode *inode, struct file *file) +{ + struct video_device *v = video_devdata(file); + struct pms_device *pd = (struct pms_device *)v; + + return test_and_set_bit(0, &pd->in_use) ? -EBUSY : 0; +} + +static int pms_exclusive_release(struct inode *inode, struct file *file) +{ + struct video_device *v = video_devdata(file); + struct pms_device *pd = (struct pms_device *)v; + + clear_bit(0, &pd->in_use); + return 0; +} + static const struct file_operations pms_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = pms_exclusive_open, + .release = pms_exclusive_release, .ioctl = pms_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -898,6 +916,7 @@ static struct video_device pms_template= { .name = "Mediavision PMS", .fops = &pms_fops, + .release = video_device_release_empty, }; static struct pms_device pms_device; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c index 3b982d963..5fa8af50b 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c @@ -135,13 +135,17 @@ int pvr2_ctrl_get_min(struct pvr2_ctrl *cptr) /* Retrieve control's default value (any type) */ -int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr) +int pvr2_ctrl_get_def(struct pvr2_ctrl *cptr, int *valptr) { int ret = 0; if (!cptr) return 0; LOCK_TAKE(cptr->hdw->big_lock); do { if (cptr->info->type == pvr2_ctl_int) { - ret = cptr->info->default_value; + if (cptr->info->get_def_value) { + ret = cptr->info->get_def_value(cptr, valptr); + } else { + *valptr = cptr->info->default_value; + } } } while(0); LOCK_GIVE(cptr->hdw->big_lock); return ret; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h index 0371ae6e6..794ff9012 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.h @@ -49,7 +49,7 @@ int pvr2_ctrl_get_max(struct pvr2_ctrl *); int pvr2_ctrl_get_min(struct pvr2_ctrl *); /* Retrieve control's default value (any type) */ -int pvr2_ctrl_get_def(struct pvr2_ctrl *); +int pvr2_ctrl_get_def(struct pvr2_ctrl *, int *valptr); /* Retrieve control's enumeration count (enum only) */ int pvr2_ctrl_get_cnt(struct pvr2_ctrl *); diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c index 88e175168..cbe2a3417 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-devattr.c @@ -489,6 +489,8 @@ static const struct pvr2_device_desc pvr2_device_751xx = { struct usb_device_id pvr2_device_table[] = { { USB_DEVICE(0x2040, 0x2900), .driver_info = (kernel_ulong_t)&pvr2_device_29xxx}, + { USB_DEVICE(0x2040, 0x2950), /* Logically identical to 2900 */ + .driver_info = (kernel_ulong_t)&pvr2_device_29xxx}, { USB_DEVICE(0x2040, 0x2400), .driver_info = (kernel_ulong_t)&pvr2_device_24xxx}, { USB_DEVICE(0x1164, 0x0622), diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index 657f86159..de7ee7264 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h @@ -82,6 +82,7 @@ struct pvr2_ctl_info { /* Control's implementation */ pvr2_ctlf_get_value get_value; /* Get its value */ + pvr2_ctlf_get_value get_def_value; /* Get its default value */ pvr2_ctlf_get_value get_min_value; /* Get minimum allowed value */ pvr2_ctlf_get_value get_max_value; /* Get maximum allowed value */ pvr2_ctlf_set_value set_value; /* Set its value */ @@ -307,6 +308,10 @@ struct pvr2_hdw { struct v4l2_tuner tuner_signal_info; int tuner_signal_stale; + /* Cropping capability info */ + struct v4l2_cropcap cropcap_info; + int cropcap_stale; + /* Video standard handling */ v4l2_std_id std_mask_eeprom; // Hardware supported selections v4l2_std_id std_mask_avail; // Which standards we may select from @@ -367,6 +372,10 @@ struct pvr2_hdw { VCREATE_DATA(bass); VCREATE_DATA(treble); VCREATE_DATA(mute); + VCREATE_DATA(cropl); + VCREATE_DATA(cropt); + VCREATE_DATA(cropw); + VCREATE_DATA(croph); VCREATE_DATA(input); VCREATE_DATA(audiomode); VCREATE_DATA(res_hor); diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 881610b60..b79829f8a 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c @@ -299,6 +299,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, unsigned int timeout,int probe_fl, void *write_data,unsigned int write_len, void *read_data,unsigned int read_len); +static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw); static void trace_stbit(const char *name,int val) @@ -403,6 +404,194 @@ static int ctrl_freq_set(struct pvr2_ctrl *cptr,int m,int v) return 0; } +static int ctrl_cropl_min_get(struct pvr2_ctrl *cptr, int *left) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *left = cap->bounds.left; + return 0; +} + +static int ctrl_cropl_max_get(struct pvr2_ctrl *cptr, int *left) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *left = cap->bounds.left; + if (cap->bounds.width > cptr->hdw->cropw_val) { + *left += cap->bounds.width - cptr->hdw->cropw_val; + } + return 0; +} + +static int ctrl_cropt_min_get(struct pvr2_ctrl *cptr, int *top) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *top = cap->bounds.top; + return 0; +} + +static int ctrl_cropt_max_get(struct pvr2_ctrl *cptr, int *top) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *top = cap->bounds.top; + if (cap->bounds.height > cptr->hdw->croph_val) { + *top += cap->bounds.height - cptr->hdw->croph_val; + } + return 0; +} + +static int ctrl_cropw_max_get(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = 0; + if (cap->bounds.width > cptr->hdw->cropl_val) { + *val = cap->bounds.width - cptr->hdw->cropl_val; + } + return 0; +} + +static int ctrl_croph_max_get(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = 0; + if (cap->bounds.height > cptr->hdw->cropt_val) { + *val = cap->bounds.height - cptr->hdw->cropt_val; + } + return 0; +} + +static int ctrl_get_cropcapbl(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = cap->bounds.left; + return 0; +} + +static int ctrl_get_cropcapbt(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = cap->bounds.top; + return 0; +} + +static int ctrl_get_cropcapbw(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = cap->bounds.width; + return 0; +} + +static int ctrl_get_cropcapbh(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = cap->bounds.height; + return 0; +} + +static int ctrl_get_cropcapdl(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = cap->defrect.left; + return 0; +} + +static int ctrl_get_cropcapdt(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = cap->defrect.top; + return 0; +} + +static int ctrl_get_cropcapdw(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = cap->defrect.width; + return 0; +} + +static int ctrl_get_cropcapdh(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = cap->defrect.height; + return 0; +} + +static int ctrl_get_cropcappan(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = cap->pixelaspect.numerator; + return 0; +} + +static int ctrl_get_cropcappad(struct pvr2_ctrl *cptr, int *val) +{ + struct v4l2_cropcap *cap = &cptr->hdw->cropcap_info; + int stat = pvr2_hdw_check_cropcap(cptr->hdw); + if (stat != 0) { + return stat; + } + *val = cap->pixelaspect.denominator; + return 0; +} + static int ctrl_vres_max_get(struct pvr2_ctrl *cptr,int *vp) { /* Actual maximum depends on the video standard in effect. */ @@ -780,6 +969,10 @@ VCREATE_FUNCS(balance) VCREATE_FUNCS(bass) VCREATE_FUNCS(treble) VCREATE_FUNCS(mute) +VCREATE_FUNCS(cropl) +VCREATE_FUNCS(cropt) +VCREATE_FUNCS(cropw) +VCREATE_FUNCS(croph) VCREATE_FUNCS(audiomode) VCREATE_FUNCS(res_hor) VCREATE_FUNCS(res_ver) @@ -850,6 +1043,72 @@ static const struct pvr2_ctl_info control_defs[] = { .default_value = 0, DEFREF(mute), DEFBOOL, + }, { + .desc = "Capture crop left margin", + .name = "crop_left", + .internal_id = PVR2_CID_CROPL, + .default_value = 0, + DEFREF(cropl), + DEFINT(-129, 340), + .get_min_value = ctrl_cropl_min_get, + .get_max_value = ctrl_cropl_max_get, + .get_def_value = ctrl_get_cropcapdl, + }, { + .desc = "Capture crop top margin", + .name = "crop_top", + .internal_id = PVR2_CID_CROPT, + .default_value = 0, + DEFREF(cropt), + DEFINT(-35, 544), + .get_min_value = ctrl_cropt_min_get, + .get_max_value = ctrl_cropt_max_get, + .get_def_value = ctrl_get_cropcapdt, + }, { + .desc = "Capture crop width", + .name = "crop_width", + .internal_id = PVR2_CID_CROPW, + .default_value = 720, + DEFREF(cropw), + .get_max_value = ctrl_cropw_max_get, + .get_def_value = ctrl_get_cropcapdw, + }, { + .desc = "Capture crop height", + .name = "crop_height", + .internal_id = PVR2_CID_CROPH, + .default_value = 480, + DEFREF(croph), + .get_max_value = ctrl_croph_max_get, + .get_def_value = ctrl_get_cropcapdh, + }, { + .desc = "Capture capability pixel aspect numerator", + .name = "cropcap_pixel_numerator", + .internal_id = PVR2_CID_CROPCAPPAN, + .get_value = ctrl_get_cropcappan, + }, { + .desc = "Capture capability pixel aspect denominator", + .name = "cropcap_pixel_denominator", + .internal_id = PVR2_CID_CROPCAPPAD, + .get_value = ctrl_get_cropcappad, + }, { + .desc = "Capture capability bounds top", + .name = "cropcap_bounds_top", + .internal_id = PVR2_CID_CROPCAPBT, + .get_value = ctrl_get_cropcapbt, + }, { + .desc = "Capture capability bounds left", + .name = "cropcap_bounds_left", + .internal_id = PVR2_CID_CROPCAPBL, + .get_value = ctrl_get_cropcapbl, + }, { + .desc = "Capture capability bounds width", + .name = "cropcap_bounds_width", + .internal_id = PVR2_CID_CROPCAPBW, + .get_value = ctrl_get_cropcapbw, + }, { + .desc = "Capture capability bounds height", + .name = "cropcap_bounds_height", + .internal_id = PVR2_CID_CROPCAPBH, + .get_value = ctrl_get_cropcapbh, },{ .desc = "Video Source", .name = "input", @@ -1323,6 +1582,17 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) if (bcnt > FIRMWARE_CHUNK_SIZE) bcnt = FIRMWARE_CHUNK_SIZE; memcpy(fw_ptr, fw_entry->data + fw_done, bcnt); /* Usbsnoop log shows that we must swap bytes... */ + /* Some background info: The data being swapped here is a + firmware image destined for the mpeg encoder chip that + lives at the other end of a USB endpoint. The encoder + chip always talks in 32 bit chunks and its storage is + organized into 32 bit words. However from the file + system to the encoder chip everything is purely a byte + stream. The firmware file's contents are always 32 bit + swapped from what the encoder expects. Thus the need + always exists to swap the bytes regardless of the endian + type of the host processor and therefore swab32() makes + the most sense. */ for (icnt = 0; icnt < bcnt/4 ; icnt++) ((u32 *)fw_ptr)[icnt] = swab32(((u32 *)fw_ptr)[icnt]); @@ -1921,7 +2191,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, const struct usb_device_id *devid) { unsigned int idx,cnt1,cnt2,m; - struct pvr2_hdw *hdw; + struct pvr2_hdw *hdw = NULL; int valid_std_mask; struct pvr2_ctrl *cptr; const struct pvr2_device_desc *hdw_desc; @@ -1931,6 +2201,16 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info); + if (hdw_desc == NULL) { + pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_create:" + " No device description pointer," + " unable to continue."); + pvr2_trace(PVR2_TRACE_INIT, "If you have a new device type," + " please contact Mike Isely <isely@pobox.com>" + " to get it included in the driver\n"); + goto fail; + } + hdw = kzalloc(sizeof(*hdw),GFP_KERNEL); pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_create: hdw=%p, type \"%s\"", hdw,hdw_desc->description); @@ -2088,6 +2368,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, valid_std_mask; } + hdw->cropcap_stale = !0; hdw->eeprom_addr = -1; hdw->unit_number = -1; hdw->v4l_minor_number_video = -1; @@ -2531,6 +2812,28 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) /* Can't commit anything until pathway is ok. */ return 0; } + /* The broadcast decoder can only scale down, so if + * res_*_dirty && crop window < output format ==> enlarge crop. + * + * The mpeg encoder receives fields of res_hor_val dots and + * res_ver_val halflines. Limits: hor<=720, ver<=576. + */ + if (hdw->res_hor_dirty && hdw->cropw_val < hdw->res_hor_val) { + hdw->cropw_val = hdw->res_hor_val; + hdw->cropw_dirty = !0; + } else if (hdw->cropw_dirty) { + hdw->res_hor_dirty = !0; /* must rescale */ + hdw->res_hor_val = min(720, hdw->cropw_val); + } + if (hdw->res_ver_dirty && hdw->croph_val < hdw->res_ver_val) { + hdw->croph_val = hdw->res_ver_val; + hdw->croph_dirty = !0; + } else if (hdw->croph_dirty) { + int nvres = hdw->std_mask_cur & V4L2_STD_525_60 ? 480 : 576; + hdw->res_ver_dirty = !0; + hdw->res_ver_val = min(nvres, hdw->croph_val); + } + /* If any of the below has changed, then we can't do the update while the pipeline is running. Pipeline must be paused first and decoder -> encoder connection be made quiescent before we @@ -2541,6 +2844,8 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) hdw->srate_dirty || hdw->res_ver_dirty || hdw->res_hor_dirty || + hdw->cropw_dirty || + hdw->croph_dirty || hdw->input_dirty || (hdw->active_stream_type != hdw->desired_stream_type)); if (disruptive_change && !hdw->state_pipeline_idle) { @@ -2610,6 +2915,9 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw) } hdw->state_pipeline_config = !0; + /* Hardware state may have changed in a way to cause the cropping + capabilities to have changed. So mark it stale, which will + cause a later re-fetch. */ trace_stbit("state_pipeline_config",hdw->state_pipeline_config); return !0; } @@ -2700,6 +3008,33 @@ void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *hdw) } +static int pvr2_hdw_check_cropcap(struct pvr2_hdw *hdw) +{ + if (!hdw->cropcap_stale) { + return 0; + } + pvr2_i2c_core_status_poll(hdw); + if (hdw->cropcap_stale) { + return -EIO; + } + return 0; +} + + +/* Return information about cropping capabilities */ +int pvr2_hdw_get_cropcap(struct pvr2_hdw *hdw, struct v4l2_cropcap *pp) +{ + int stat = 0; + LOCK_TAKE(hdw->big_lock); + stat = pvr2_hdw_check_cropcap(hdw); + if (!stat) { + memcpy(pp, &hdw->cropcap_info, sizeof(hdw->cropcap_info)); + } + LOCK_GIVE(hdw->big_lock); + return stat; +} + + /* Return information about the tuner */ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *hdw,struct v4l2_tuner *vtp) { diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 4e60f6262..29fb0729d 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.h @@ -37,6 +37,16 @@ #define PVR2_CID_FREQUENCY 6 #define PVR2_CID_HRES 7 #define PVR2_CID_VRES 8 +#define PVR2_CID_CROPL 9 +#define PVR2_CID_CROPT 10 +#define PVR2_CID_CROPW 11 +#define PVR2_CID_CROPH 12 +#define PVR2_CID_CROPCAPPAN 13 +#define PVR2_CID_CROPCAPPAD 14 +#define PVR2_CID_CROPCAPBL 15 +#define PVR2_CID_CROPCAPBT 16 +#define PVR2_CID_CROPCAPBW 17 +#define PVR2_CID_CROPCAPBH 18 /* Legal values for the INPUT state variable */ #define PVR2_CVAL_INPUT_TV 0 @@ -176,6 +186,9 @@ void pvr2_hdw_execute_tuner_poll(struct pvr2_hdw *); /* Return information about the tuner */ int pvr2_hdw_get_tuner_status(struct pvr2_hdw *,struct v4l2_tuner *); +/* Return information about cropping capabilities */ +int pvr2_hdw_get_cropcap(struct pvr2_hdw *, struct v4l2_cropcap *); + /* Query device and see if it thinks it is on a high-speed USB link */ int pvr2_hdw_is_hsm(struct pvr2_hdw *); diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c index 25e611b2e..1b1424955 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-chips-v4l2.c @@ -38,8 +38,9 @@ #define OP_VOLUME 3 #define OP_FREQ 4 #define OP_AUDIORATE 5 -#define OP_SIZE 6 -#define OP_LOG 7 +#define OP_CROP 6 +#define OP_SIZE 7 +#define OP_LOG 8 static const struct pvr2_i2c_op * const ops[] = { [OP_STANDARD] = &pvr2_i2c_op_v4l2_standard, @@ -47,6 +48,7 @@ static const struct pvr2_i2c_op * const ops[] = { [OP_BCSH] = &pvr2_i2c_op_v4l2_bcsh, [OP_VOLUME] = &pvr2_i2c_op_v4l2_volume, [OP_FREQ] = &pvr2_i2c_op_v4l2_frequency, + [OP_CROP] = &pvr2_i2c_op_v4l2_crop, [OP_SIZE] = &pvr2_i2c_op_v4l2_size, [OP_LOG] = &pvr2_i2c_op_v4l2_log, }; @@ -60,6 +62,7 @@ void pvr2_i2c_probe(struct pvr2_hdw *hdw,struct pvr2_i2c_client *cp) (1 << OP_BCSH) | (1 << OP_VOLUME) | (1 << OP_FREQ) | + (1 << OP_CROP) | (1 << OP_SIZE) | (1 << OP_LOG)); cp->status_poll = pvr2_v4l2_cmd_status_poll; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c index d715c80ef..ab703d6d5 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.c @@ -38,6 +38,7 @@ static void set_standard(struct pvr2_hdw *hdw) pvr2_i2c_core_cmd(hdw,VIDIOC_S_STD,&vs); } hdw->tuner_signal_stale = !0; + hdw->cropcap_stale = !0; } @@ -234,6 +235,37 @@ const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size = { }; +static void set_crop(struct pvr2_hdw *hdw) +{ + struct v4l2_crop crop; + + memset(&crop, 0, sizeof crop); + crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + crop.c.left = hdw->cropl_val; + crop.c.top = hdw->cropt_val; + crop.c.height = hdw->croph_val; + crop.c.width = hdw->cropw_val; + + pvr2_trace(PVR2_TRACE_CHIPS, + "i2c v4l2 set_crop crop=%d:%d:%d:%d", + crop.c.width, crop.c.height, crop.c.left, crop.c.top); + + pvr2_i2c_core_cmd(hdw, VIDIOC_S_CROP, &crop); +} + +static int check_crop(struct pvr2_hdw *hdw) +{ + return (hdw->cropl_dirty || hdw->cropt_dirty || + hdw->cropw_dirty || hdw->croph_dirty); +} + +const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop = { + .check = check_crop, + .update = set_crop, + .name = "v4l2_crop", +}; + + static void do_log(struct pvr2_hdw *hdw) { pvr2_trace(PVR2_TRACE_CHIPS,"i2c v4l2 do_log()"); @@ -264,7 +296,19 @@ void pvr2_v4l2_cmd_stream(struct pvr2_i2c_client *cp,int fl) void pvr2_v4l2_cmd_status_poll(struct pvr2_i2c_client *cp) { - pvr2_i2c_client_cmd(cp,VIDIOC_G_TUNER,&cp->hdw->tuner_signal_info); + int stat; + struct pvr2_hdw *hdw = cp->hdw; + if (hdw->cropcap_stale) { + hdw->cropcap_info.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + stat = pvr2_i2c_client_cmd(cp, VIDIOC_CROPCAP, + &hdw->cropcap_info); + if (stat == 0) { + /* Check was successful, so the data is no + longer considered stale. */ + hdw->cropcap_stale = 0; + } + } + pvr2_i2c_client_cmd(cp, VIDIOC_G_TUNER, &hdw->tuner_signal_info); } diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h index 7fa38683b..eb744a206 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-cmd-v4l2.h @@ -29,6 +29,7 @@ extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_radio; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_bcsh; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_volume; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_frequency; +extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_crop; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_size; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_audiomode; extern const struct pvr2_i2c_op pvr2_i2c_op_v4l2_log; diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c index 9159686c3..edce8fc34 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c @@ -902,7 +902,7 @@ static unsigned int pvr2_i2c_client_describe(struct pvr2_i2c_client *cp, if ((detail & PVR2_I2C_DETAIL_CTLMASK) && cp->ctl_mask) { unsigned int idx; unsigned long msk,sm; - int spcfl; + bcnt = scnprintf(buf,maxlen," ["); ccnt += bcnt; buf += bcnt; maxlen -= bcnt; sm = 0; @@ -966,6 +966,7 @@ static int pvr2_i2c_attach_inform(struct i2c_client *client) INIT_LIST_HEAD(&cp->list); cp->client = client; mutex_lock(&hdw->i2c_list_lock); do { + hdw->cropcap_stale = !0; list_add_tail(&cp->list,&hdw->i2c_clients); hdw->i2c_pend_types |= PVR2_I2C_PEND_DETECT; } while (0); mutex_unlock(&hdw->i2c_list_lock); @@ -980,6 +981,7 @@ static int pvr2_i2c_detach_inform(struct i2c_client *client) unsigned long amask = 0; int foundfl = 0; mutex_lock(&hdw->i2c_list_lock); do { + hdw->cropcap_stale = !0; list_for_each_entry_safe(cp, ncp, &hdw->i2c_clients, list) { if (cp->client == client) { trace_i2c("pvr2_i2c_detach" @@ -1021,22 +1023,32 @@ static struct i2c_adapter pvr2_i2c_adap_template = { .client_unregister = pvr2_i2c_detach_inform, }; -static void do_i2c_scan(struct pvr2_hdw *hdw) + +/* Return true if device exists at given address */ +static int do_i2c_probe(struct pvr2_hdw *hdw, int addr) { struct i2c_msg msg[1]; - int i,rc; + int rc; msg[0].addr = 0; msg[0].flags = I2C_M_RD; msg[0].len = 0; msg[0].buf = NULL; - printk("%s: i2c scan beginning\n",hdw->name); + msg[0].addr = addr; + rc = i2c_transfer(&hdw->i2c_adap, msg, ARRAY_SIZE(msg)); + return rc == 1; +} + +static void do_i2c_scan(struct pvr2_hdw *hdw) +{ + int i; + printk(KERN_INFO "%s: i2c scan beginning\n", hdw->name); for (i = 0; i < 128; i++) { - msg[0].addr = i; - rc = i2c_transfer(&hdw->i2c_adap,msg, ARRAY_SIZE(msg)); - if (rc != 1) continue; - printk("%s: i2c scan: found device @ 0x%x\n",hdw->name,i); + if (do_i2c_probe(hdw, i)) { + printk(KERN_INFO "%s: i2c scan: found device @ 0x%x\n", + hdw->name, i); + } } - printk("%s: i2c scan done.\n",hdw->name); + printk(KERN_INFO "%s: i2c scan done.\n", hdw->name); } void pvr2_i2c_core_init(struct pvr2_hdw *hdw) @@ -1055,8 +1067,6 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) hdw->i2c_func[0x18] = i2c_black_hole; } else if (ir_mode[hdw->unit_number] == 1) { 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; } } @@ -1081,6 +1091,16 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) mutex_init(&hdw->i2c_list_lock); hdw->i2c_linked = !0; i2c_add_adapter(&hdw->i2c_adap); + if (hdw->i2c_func[0x18] == i2c_24xxx_ir) { + /* Probe for a different type of IR receiver on this + device. If present, disable the emulated IR receiver. */ + if (do_i2c_probe(hdw, 0x71)) { + pvr2_trace(PVR2_TRACE_INFO, + "Device has newer IR hardware;" + " disabling unneeded virtual IR device"); + hdw->i2c_func[0x18] = NULL; + } + } if (i2c_scan) do_i2c_scan(hdw); } diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c index 90cb36435..16461dd92 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-sysfs.c @@ -66,6 +66,7 @@ struct pvr2_sysfs_ctl_item { struct device_attribute attr_type; struct device_attribute attr_min; struct device_attribute attr_max; + struct device_attribute attr_def; struct device_attribute attr_enum; struct device_attribute attr_bits; struct device_attribute attr_val; @@ -146,6 +147,23 @@ static ssize_t show_max(struct device *class_dev, return scnprintf(buf, PAGE_SIZE, "%ld\n", val); } +static ssize_t show_def(struct device *class_dev, + struct device_attribute *attr, + char *buf) +{ + struct pvr2_sysfs_ctl_item *cip; + int val; + int ret; + cip = container_of(attr, struct pvr2_sysfs_ctl_item, attr_def); + ret = pvr2_ctrl_get_def(cip->cptr, &val); + pvr2_sysfs_trace("pvr2_sysfs(%p) show_def(cid=%d) is %d, stat=%d", + cip->chptr, cip->ctl_id, val, ret); + if (ret < 0) { + return ret; + } + return scnprintf(buf, PAGE_SIZE, "%d\n", val); +} + static ssize_t show_val_norm(struct device *class_dev, struct device_attribute *attr, char *buf) @@ -321,6 +339,10 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) cip->attr_max.attr.mode = S_IRUGO; cip->attr_max.show = show_max; + cip->attr_def.attr.name = "def_val"; + cip->attr_def.attr.mode = S_IRUGO; + cip->attr_def.show = show_def; + cip->attr_val.attr.name = "cur_val"; cip->attr_val.attr.mode = S_IRUGO; @@ -344,6 +366,7 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id) cip->attr_gen[acnt++] = &cip->attr_name.attr; cip->attr_gen[acnt++] = &cip->attr_type.attr; cip->attr_gen[acnt++] = &cip->attr_val.attr; + cip->attr_gen[acnt++] = &cip->attr_def.attr; cip->attr_val.show = show_val_norm; cip->attr_val.store = store_val_norm; if (pvr2_ctrl_has_custom_symbols(cptr)) { diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index c1cc0e88b..429c96d4f 100644 --- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c @@ -534,7 +534,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, lmin = pvr2_ctrl_get_min(hcp); lmax = pvr2_ctrl_get_max(hcp); - ldef = pvr2_ctrl_get_def(hcp); + pvr2_ctrl_get_def(hcp, &ldef); if (w == -1) { w = ldef; } else if (w < lmin) { @@ -544,7 +544,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, } lmin = pvr2_ctrl_get_min(vcp); lmax = pvr2_ctrl_get_max(vcp); - ldef = pvr2_ctrl_get_def(vcp); + pvr2_ctrl_get_def(vcp, &ldef); if (h == -1) { h = ldef; } else if (h < lmin) { @@ -605,6 +605,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, case VIDIOC_QUERYCTRL: { struct pvr2_ctrl *cptr; + int val; struct v4l2_queryctrl *vc = (struct v4l2_queryctrl *)arg; ret = 0; if (vc->id & V4L2_CTRL_FLAG_NEXT_CTRL) { @@ -628,7 +629,8 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, pvr2_ctrl_get_desc(cptr)); strlcpy(vc->name,pvr2_ctrl_get_desc(cptr),sizeof(vc->name)); vc->flags = pvr2_ctrl_get_v4lflags(cptr); - vc->default_value = pvr2_ctrl_get_def(cptr); + pvr2_ctrl_get_def(cptr, &val); + vc->default_value = val; switch (pvr2_ctrl_get_type(cptr)) { case pvr2_ctl_enum: vc->type = V4L2_CTRL_TYPE_MENU; @@ -754,6 +756,92 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, break; } + case VIDIOC_CROPCAP: + { + struct v4l2_cropcap *cap = (struct v4l2_cropcap *)arg; + if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = -EINVAL; + break; + } + ret = pvr2_hdw_get_cropcap(hdw, cap); + cap->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* paranoia */ + break; + } + case VIDIOC_G_CROP: + { + struct v4l2_crop *crop = (struct v4l2_crop *)arg; + int val = 0; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = -EINVAL; + break; + } + ret = pvr2_ctrl_get_value( + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), &val); + if (ret != 0) { + ret = -EINVAL; + break; + } + crop->c.left = val; + ret = pvr2_ctrl_get_value( + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), &val); + if (ret != 0) { + ret = -EINVAL; + break; + } + crop->c.top = val; + ret = pvr2_ctrl_get_value( + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), &val); + if (ret != 0) { + ret = -EINVAL; + break; + } + crop->c.width = val; + ret = pvr2_ctrl_get_value( + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), &val); + if (ret != 0) { + ret = -EINVAL; + break; + } + crop->c.height = val; + } + case VIDIOC_S_CROP: + { + struct v4l2_crop *crop = (struct v4l2_crop *)arg; + struct v4l2_cropcap cap; + if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ret = -EINVAL; + break; + } + cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + ret = pvr2_ctrl_set_value( + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPL), + crop->c.left); + if (ret != 0) { + ret = -EINVAL; + break; + } + ret = pvr2_ctrl_set_value( + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPT), + crop->c.top); + if (ret != 0) { + ret = -EINVAL; + break; + } + ret = pvr2_ctrl_set_value( + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPW), + crop->c.width); + if (ret != 0) { + ret = -EINVAL; + break; + } + ret = pvr2_ctrl_set_value( + pvr2_hdw_get_ctrl_by_id(hdw, PVR2_CID_CROPH), + crop->c.height); + if (ret != 0) { + ret = -EINVAL; + break; + } + } case VIDIOC_LOG_STATUS: { pvr2_hdw_trigger_module_log(hdw); @@ -933,7 +1021,6 @@ 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; @@ -944,13 +1031,11 @@ 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; } @@ -980,7 +1065,6 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) fhp); kfree(fhp); - unlock_kernel(); return ret; } @@ -997,7 +1081,6 @@ 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; @@ -1021,7 +1104,6 @@ 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; } diff --git a/linux/drivers/media/video/pwc/pwc-ctrl.c b/linux/drivers/media/video/pwc/pwc-ctrl.c index 1cccd5c77..dbc560742 100644 --- a/linux/drivers/media/video/pwc/pwc-ctrl.c +++ b/linux/drivers/media/video/pwc/pwc-ctrl.c @@ -1635,15 +1635,15 @@ int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) case VIDIOCPWCGVIDCMD: { - ARG_DEF(struct pwc_video_command, cmd); - - ARGR(cmd).type = pdev->type; - ARGR(cmd).release = pdev->release; - ARGR(cmd).command_len = pdev->cmd_len; - memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len); - ARGR(cmd).bandlength = pdev->vbandlength; - ARGR(cmd).frame_size = pdev->frame_size; - ARG_OUT(cmd) + ARG_DEF(struct pwc_video_command, vcmd); + + ARGR(vcmd).type = pdev->type; + ARGR(vcmd).release = pdev->release; + ARGR(vcmd).command_len = pdev->cmd_len; + memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len); + ARGR(vcmd).bandlength = pdev->vbandlength; + ARGR(vcmd).frame_size = pdev->frame_size; + ARG_OUT(vcmd) break; } /* diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c index f005e2338..69917b2f9 100644 --- a/linux/drivers/media/video/pwc/pwc-if.c +++ b/linux/drivers/media/video/pwc/pwc-if.c @@ -1116,7 +1116,7 @@ static int pwc_video_open(struct inode *inode, struct file *file) PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev); - pdev = (struct pwc_device *)vdev->priv; + pdev = video_get_drvdata(vdev); BUG_ON(!pdev); if (pdev->vopen) { PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n"); @@ -1237,7 +1237,7 @@ static int pwc_video_close(struct inode *inode, struct file *file) PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); lock_kernel(); - pdev = (struct pwc_device *)vdev->priv; + pdev = video_get_drvdata(vdev); if (pdev->vopen == 0) PWC_DEBUG_MODULE("video_close() called on closed device?\n"); @@ -1308,7 +1308,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf, vdev, buf, count); if (vdev == NULL) return -EFAULT; - pdev = vdev->priv; + pdev = video_get_drvdata(vdev); if (pdev == NULL) return -EFAULT; @@ -1390,7 +1390,7 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait) if (vdev == NULL) return -EFAULT; - pdev = vdev->priv; + pdev = video_get_drvdata(vdev); if (pdev == NULL) return -EFAULT; @@ -1412,7 +1412,7 @@ static int pwc_video_ioctl(struct inode *inode, struct file *file, if (!vdev) goto out; - pdev = vdev->priv; + pdev = video_get_drvdata(vdev); mutex_lock(&pdev->modlock); if (!pdev->unplugged) @@ -1432,7 +1432,7 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) int index; PWC_DEBUG_MEMORY(">> %s\n", __func__); - pdev = vdev->priv; + pdev = video_get_drvdata(vdev); size = vma->vm_end - vma->vm_start; start = vma->vm_start; diff --git a/linux/drivers/media/video/pwc/pwc-v4l.c b/linux/drivers/media/video/pwc/pwc-v4l.c index 174288987..76a1376c9 100644 --- a/linux/drivers/media/video/pwc/pwc-v4l.c +++ b/linux/drivers/media/video/pwc/pwc-v4l.c @@ -346,7 +346,7 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file, if (vdev == NULL) return -EFAULT; - pdev = vdev->priv; + pdev = video_get_drvdata(vdev); if (pdev == NULL) return -EFAULT; diff --git a/linux/drivers/media/video/s2255drv.c b/linux/drivers/media/video/s2255drv.c index 939edff48..8fae00dac 100644 --- a/linux/drivers/media/video/s2255drv.c +++ b/linux/drivers/media/video/s2255drv.c @@ -59,6 +59,8 @@ +/* default JPEG quality */ +#define S2255_DEF_JPEG_QUAL 50 /* vendor request in */ #define S2255_VR_IN 0 /* vendor request out */ @@ -68,20 +70,21 @@ /* USB endpoint number for configuring the device */ #define S2255_CONFIG_EP 2 /* maximum time for DSP to start responding after last FW word loaded(ms) */ -#define S2255_DSP_BOOTTIME 400 +#define S2255_DSP_BOOTTIME 800 /* maximum time to wait for firmware to load (ms) */ #define S2255_LOAD_TIMEOUT (5000 + S2255_DSP_BOOTTIME) #define S2255_DEF_BUFS 16 +#define S2255_SETMODE_TIMEOUT 500 #define MAX_CHANNELS 4 -#define FRAME_MARKER 0x2255DA4AL -#define MAX_PIPE_USBBLOCK (40 * 1024) -#define DEFAULT_PIPE_USBBLOCK (16 * 1024) +#define S2255_MARKER_FRAME 0x2255DA4AL +#define S2255_MARKER_RESPONSE 0x2255ACACL +#define S2255_USB_XFER_SIZE (16 * 1024) #define MAX_CHANNELS 4 #define MAX_PIPE_BUFFERS 1 #define SYS_FRAMES 4 /* maximum size is PAL full size plus room for the marker header(s) */ -#define SYS_FRAMES_MAXSIZE (720 * 288 * 2 * 2 + 4096) -#define DEF_USB_BLOCK (4096) +#define SYS_FRAMES_MAXSIZE (720*288*2*2 + 4096) +#define DEF_USB_BLOCK S2255_USB_XFER_SIZE #define LINE_SZ_4CIFS_NTSC 640 #define LINE_SZ_2CIFS_NTSC 640 #define LINE_SZ_1CIFS_NTSC 320 @@ -109,6 +112,9 @@ #define COLOR_YUVPL 1 /* YUV planar */ #define COLOR_YUVPK 2 /* YUV packed */ #define COLOR_Y8 4 /* monochrome */ +#define COLOR_JPG 5 /* JPEG */ +#define MASK_COLOR 0xff +#define MASK_JPG_QUALITY 0xff00 /* frame decimation. Not implemented by V4L yet(experimental in V4L) */ #define FDEC_1 1 /* capture every frame. default */ @@ -149,16 +155,14 @@ struct s2255_mode { u32 restart; /* if DSP requires restart */ }; -/* frame structure */ -#define FRAME_STATE_UNUSED 0 -#define FRAME_STATE_FILLING 1 -#define FRAME_STATE_FULL 2 +#define S2255_READ_IDLE 0 +#define S2255_READ_FRAME 1 +/* frame structure */ struct s2255_framei { unsigned long size; - - unsigned long ulState; /* ulState ==0 unused, 1 being filled, 2 full */ + unsigned long ulState; /* ulState:S2255_READ_IDLE, S2255_READ_FRAME*/ void *lpvbits; /* image data */ unsigned long cur_size; /* current data copied to it */ }; @@ -189,6 +193,10 @@ struct s2255_dmaqueue { #define S2255_FW_FAILED 3 #define S2255_FW_DISCONNECTING 4 +#define S2255_FW_MARKER 0x22552f2f +/* 2255 read states */ +#define S2255_READ_IDLE 0 +#define S2255_READ_FRAME 1 struct s2255_fw { int fw_loaded; int fw_size; @@ -196,7 +204,6 @@ struct s2255_fw { atomic_t fw_state; void *pfw_data; wait_queue_head_t wait_fw; - struct timer_list dsp_wait; const struct firmware *fw; }; @@ -238,15 +245,27 @@ struct s2255_dev { struct s2255_pipeinfo pipes[MAX_PIPE_BUFFERS]; struct s2255_bufferi buffer[MAX_CHANNELS]; struct s2255_mode mode[MAX_CHANNELS]; + /* jpeg compression */ + struct v4l2_jpegcompression jc[MAX_CHANNELS]; const struct s2255_fmt *cur_fmt[MAX_CHANNELS]; int cur_frame[MAX_CHANNELS]; int last_frame[MAX_CHANNELS]; u32 cc; /* current channel */ int b_acquire[MAX_CHANNELS]; + /* allocated image size */ unsigned long req_image_size[MAX_CHANNELS]; + /* received packet size */ + unsigned long pkt_size[MAX_CHANNELS]; int bad_payload[MAX_CHANNELS]; unsigned long frame_count[MAX_CHANNELS]; int frame_ready; + /* if JPEG image */ + int jpg_size[MAX_CHANNELS]; + /* if channel configured to default state */ + int chn_configured[MAX_CHANNELS]; + wait_queue_head_t wait_setmode[MAX_CHANNELS]; + int setmode_ready[MAX_CHANNELS]; + int chn_ready; struct kref kref; spinlock_t slock; }; @@ -307,12 +326,16 @@ static void s2255_stop_readpipe(struct s2255_dev *dev); static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn); static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn); static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf, - int chn); + int chn, int jpgsize); static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn, struct s2255_mode *mode); static int s2255_board_shutdown(struct s2255_dev *dev); static void s2255_exit_v4l(struct s2255_dev *dev); -static void s2255_fwload_start(struct s2255_dev *dev); +static void s2255_fwload_start(struct s2255_dev *dev, int reset); +static void s2255_destroy(struct kref *kref); +static long s2255_vendor_req(struct s2255_dev *dev, unsigned char req, + u16 index, u16 value, void *buf, + s32 buf_len, int bOut); #define dprintk(level, fmt, arg...) \ do { \ @@ -408,6 +431,10 @@ static const struct s2255_fmt formats[] = { .fourcc = V4L2_PIX_FMT_UYVY, .depth = 16 }, { + .name = "JPG", + .fourcc = V4L2_PIX_FMT_JPEG, + .depth = 24 + }, { .name = "8bpp GREY", .fourcc = V4L2_PIX_FMT_GREY, .depth = 8 @@ -465,6 +492,13 @@ static void planar422p_to_yuv_packed(const unsigned char *in, return; } +static void s2255_reset_dsppower(struct s2255_dev *dev) +{ + s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b0b, NULL, 0, 1); + msleep(10); + s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1); + return; +} /* kickstarts the firmware loading. from probe */ @@ -481,18 +515,6 @@ static void s2255_timer(unsigned long user_data) } } -/* called when DSP is up and running. DSP is guaranteed to - be running after S2255_DSP_BOOTTIME */ -static void s2255_dsp_running(unsigned long user_data) -{ - struct s2255_fw *data = (struct s2255_fw *)user_data; - dprintk(1, "dsp running\n"); - atomic_set(&data->fw_state, S2255_FW_SUCCESS); - wake_up(&data->wait_fw); - printk(KERN_INFO "s2255: firmware loaded successfully\n"); - return; -} - /* this loads the firmware asynchronously. Originally this was done synchroously in probe. @@ -550,19 +572,14 @@ static void s2255_fwchunk_complete(struct urb *urb) } data->fw_loaded += len; } else { - init_timer(&data->dsp_wait); - data->dsp_wait.function = s2255_dsp_running; - data->dsp_wait.data = (unsigned long)data; atomic_set(&data->fw_state, S2255_FW_LOADED_DSPWAIT); - mod_timer(&data->dsp_wait, msecs_to_jiffies(S2255_DSP_BOOTTIME) - + jiffies); } dprintk(100, "2255 complete done\n"); return; } -static int s2255_got_frame(struct s2255_dev *dev, int chn) +static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize) { struct s2255_dmaqueue *dma_q = &dev->vidq[chn]; struct s2255_buffer *buf; @@ -587,8 +604,7 @@ static int s2255_got_frame(struct s2255_dev *dev, int chn) list_del(&buf->vb.queue); do_gettimeofday(&buf->vb.ts); dprintk(100, "[%p/%d] wakeup\n", buf, buf->vb.i); - - s2255_fillbuff(dev, buf, dma_q->channel); + s2255_fillbuff(dev, buf, dma_q->channel, jpgsize); wake_up(&buf->vb.done); dprintk(2, "wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i); unlock: @@ -622,7 +638,7 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc) * */ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf, - int chn) + int chn, int jpgsize) { int pos = 0; struct timeval ts; @@ -650,6 +666,10 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf, case V4L2_PIX_FMT_GREY: memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height); break; + case V4L2_PIX_FMT_JPEG: + buf->vb.size = jpgsize; + memcpy(vbuf, tmpbuf, buf->vb.size); + break; case V4L2_PIX_FMT_YUV422P: memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height * 2); @@ -658,9 +678,6 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf, printk(KERN_DEBUG "s2255: unknown format?\n"); } dev->last_frame[chn] = -1; - /* done with the frame, free it */ - frm->ulState = 0; - dprintk(4, "freeing buffer\n"); } else { printk(KERN_ERR "s2255: =======no frame\n"); return; @@ -1022,6 +1039,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, case V4L2_PIX_FMT_GREY: fh->mode.color = COLOR_Y8; break; + case V4L2_PIX_FMT_JPEG: + fh->mode.color = COLOR_JPG | + (fh->dev->jc[fh->channel].quality << 8); + break; case V4L2_PIX_FMT_YUV422P: fh->mode.color = COLOR_YUVPL; break; @@ -1140,7 +1161,7 @@ static u32 get_transfer_size(struct s2255_mode *mode) } } outImageSize = linesPerFrame * pixelsPerLine; - if (mode->color != COLOR_Y8) { + if ((mode->color & MASK_COLOR) != COLOR_Y8) { /* 2 bytes/pixel if not monochrome */ outImageSize *= 2; } @@ -1186,12 +1207,17 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn, u32 *buffer; unsigned long chn_rev; + mutex_lock(&dev->lock); chn_rev = G_chnmap[chn]; dprintk(3, "mode scale [%ld] %p %d\n", chn, mode, mode->scale); dprintk(3, "mode scale [%ld] %p %d\n", chn, &dev->mode[chn], dev->mode[chn].scale); dprintk(2, "mode contrast %x\n", mode->contrast); + /* if JPEG, set the quality */ + if ((mode->color & MASK_COLOR) == COLOR_JPG) + mode->color = (dev->jc[chn].quality << 8) | COLOR_JPG; + /* save the mode */ dev->mode[chn] = *mode; dev->req_image_size[chn] = get_transfer_size(mode); @@ -1200,6 +1226,7 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn, buffer = kzalloc(512, GFP_KERNEL); if (buffer == NULL) { dev_err(&dev->udev->dev, "out of mem\n"); + mutex_unlock(&dev->lock); return -ENOMEM; } @@ -1215,12 +1242,20 @@ static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn, dprintk(1, "set mode done chn %lu, %d\n", chn, res); /* wait at least 3 frames before continuing */ - if (mode->restart) - msleep(125); + if (mode->restart) { + dev->setmode_ready[chn] = 0; + wait_event_timeout(dev->wait_setmode[chn], + (dev->setmode_ready[chn] != 0), + msecs_to_jiffies(S2255_SETMODE_TIMEOUT)); + if (dev->setmode_ready[chn] != 1) { + printk(KERN_DEBUG "s2255: no set mode response\n"); + res = -EFAULT; + } + } /* clear the restart flag */ dev->mode[chn].restart = 0; - + mutex_unlock(&dev->lock); return res; } @@ -1270,7 +1305,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) dev->bad_payload[chn] = 0; dev->cur_frame[chn] = 0; for (j = 0; j < SYS_FRAMES; j++) { - dev->buffer[chn].frame[j].ulState = 0; + dev->buffer[chn].frame[j].ulState = S2255_READ_IDLE; dev->buffer[chn].frame[j].cur_size = 0; } res = videobuf_streamon(&fh->vb_vidq); @@ -1446,6 +1481,27 @@ static int vidioc_s_ctrl(struct file *file, void *priv, return -EINVAL; } +static int vidioc_g_jpegcomp(struct file *file, void *priv, + struct v4l2_jpegcompression *jc) +{ + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + *jc = dev->jc[fh->channel]; + dprintk(2, "getting jpegcompression, quality %d\n", jc->quality); + return 0; +} + +static int vidioc_s_jpegcomp(struct file *file, void *priv, + struct v4l2_jpegcompression *jc) +{ + struct s2255_fh *fh = priv; + struct s2255_dev *dev = fh->dev; + if (jc->quality < 0 || jc->quality > 100) + return -EINVAL; + dev->jc[fh->channel].quality = jc->quality; + dprintk(2, "setting jpeg quality %d\n", jc->quality); + return 0; +} static int s2255_open(struct inode *inode, struct file *file) { int minor = iminor(inode); @@ -1455,6 +1511,7 @@ static int s2255_open(struct inode *inode, struct file *file) enum v4l2_buf_type type = 0; int i = 0; int cur_channel = -1; + int state; dprintk(1, "s2255: open called (minor=%d)\n", minor); lock_kernel(); @@ -1471,47 +1528,77 @@ 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"); + printk(KERN_INFO "s2255: openv4l no dev\n"); return -ENODEV; } + if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_DISCONNECTING) { + unlock_kernel(); + printk(KERN_INFO "disconnecting\n"); + return -ENODEV; + } + kref_get(&dev->kref); mutex_lock(&dev->open_lock); dev->users[cur_channel]++; dprintk(4, "s2255: open_handles %d\n", dev->users[cur_channel]); - if (atomic_read(&dev->fw_data->fw_state) == S2255_FW_FAILED) { + switch (atomic_read(&dev->fw_data->fw_state)) { + case S2255_FW_FAILED: err("2255 firmware load failed. retrying.\n"); - s2255_fwload_start(dev); + s2255_fwload_start(dev, 1); wait_event_timeout(dev->fw_data->wait_fw, - (atomic_read(&dev->fw_data->fw_state) - != S2255_FW_NOTLOADED), + ((atomic_read(&dev->fw_data->fw_state) + == S2255_FW_SUCCESS) || + (atomic_read(&dev->fw_data->fw_state) + == S2255_FW_DISCONNECTING)), msecs_to_jiffies(S2255_LOAD_TIMEOUT)); - if (atomic_read(&dev->fw_data->fw_state) - != S2255_FW_SUCCESS) { - 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) { + break; + case S2255_FW_NOTLOADED: + case S2255_FW_LOADED_DSPWAIT: /* give S2255_LOAD_TIMEOUT time for firmware to load in case driver loaded and then device immediately opened */ printk(KERN_INFO "%s waiting for firmware load\n", __func__); wait_event_timeout(dev->fw_data->wait_fw, - (atomic_read(&dev->fw_data->fw_state) - != S2255_FW_NOTLOADED), - msecs_to_jiffies(S2255_LOAD_TIMEOUT)); - if (atomic_read(&dev->fw_data->fw_state) - != 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; + ((atomic_read(&dev->fw_data->fw_state) + == S2255_FW_SUCCESS) || + (atomic_read(&dev->fw_data->fw_state) + == S2255_FW_DISCONNECTING)), + msecs_to_jiffies(S2255_LOAD_TIMEOUT)); + break; + case S2255_FW_SUCCESS: + default: + break; + } + state = atomic_read(&dev->fw_data->fw_state); + if (state != S2255_FW_SUCCESS) { + int rc; + switch (state) { + case S2255_FW_FAILED: + printk(KERN_INFO "2255 FW load failed. %d\n", state); + rc = -ENODEV; + break; + case S2255_FW_DISCONNECTING: + printk(KERN_INFO "%s: disconnecting\n", __func__); + rc = -ENODEV; + break; + case S2255_FW_LOADED_DSPWAIT: + case S2255_FW_NOTLOADED: + printk(KERN_INFO "%s: firmware not loaded yet" + "please try again later\n", + __func__); + rc = -EAGAIN; + break; + default: + printk(KERN_INFO "%s: unknown state\n", __func__); + rc = -EFAULT; + break; } + dev->users[cur_channel]--; + mutex_unlock(&dev->open_lock); + kref_put(&dev->kref, s2255_destroy); + unlock_kernel(); + return rc; } /* allocate + initialize per filehandle data */ @@ -1519,6 +1606,7 @@ static int s2255_open(struct inode *inode, struct file *file) if (NULL == fh) { dev->users[cur_channel]--; mutex_unlock(&dev->open_lock); + kref_put(&dev->kref, s2255_destroy); unlock_kernel(); return -ENOMEM; } @@ -1533,6 +1621,13 @@ static int s2255_open(struct inode *inode, struct file *file) fh->height = NUM_LINES_4CIFS_NTSC * 2; fh->channel = cur_channel; + /* configure channel to default state */ + if (!dev->chn_configured[cur_channel]) { + s2255_set_mode(dev, cur_channel, &fh->mode); + dev->chn_configured[cur_channel] = 1; + } + + /* Put all controls at a sane state */ for (i = 0; i < ARRAY_SIZE(s2255_qctrl); i++) qctl_regs[i] = s2255_qctrl[i].default_value; @@ -1551,7 +1646,6 @@ static int s2255_open(struct inode *inode, struct file *file) V4L2_FIELD_INTERLACED, sizeof(struct s2255_buffer), fh); - kref_get(&dev->kref); mutex_unlock(&dev->open_lock); unlock_kernel(); return 0; @@ -1575,30 +1669,24 @@ static unsigned int s2255_poll(struct file *file, static void s2255_destroy(struct kref *kref) { struct s2255_dev *dev = to_s2255_dev(kref); + struct list_head *list; + int i; if (!dev) { 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 */ + for (i = 0; i < MAX_CHANNELS; i++) { + dev->setmode_ready[i] = 1; + wake_up(&dev->wait_setmode[i]); + } mutex_lock(&dev->open_lock); + /* reset the DSP so firmware can be reload next time */ + s2255_reset_dsppower(dev); s2255_exit_v4l(dev); - /* - * 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 */ @@ -1608,23 +1696,19 @@ static void s2255_destroy(struct kref *kref) usb_free_urb(dev->fw_data->fw_urb); dev->fw_data->fw_urb = NULL; } - - /* - * delete the dsp_wait timer, which sets the firmware - * state on completion. This is done before fw_data - * is freed below. - */ - - del_timer(&dev->fw_data->dsp_wait); /* only started in .open */ - 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__); kfree(dev); + + while (!list_empty(&s2255_devlist)) { + list = s2255_devlist.next; + list_del(list); + } + mutex_unlock(&dev->open_lock); } static int s2255_close(struct inode *inode, struct file *file) @@ -1708,6 +1792,8 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = { #ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidioc_cgmbuf, #endif + .vidioc_s_jpegcomp = vidioc_s_jpegcomp, + .vidioc_g_jpegcomp = vidioc_g_jpegcomp, }; static struct video_device template = { @@ -1746,7 +1832,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev) ret = video_register_device(dev->vdev[i], VFL_TYPE_GRABBER, cur_nr + i); - dev->vdev[i]->priv = dev; + video_set_drvdata(dev->vdev[i], dev); if (ret != 0) { dev_err(&dev->udev->dev, @@ -1760,18 +1846,16 @@ static int s2255_probe_v4l(struct s2255_dev *dev) static void s2255_exit_v4l(struct s2255_dev *dev) { - struct list_head *list; + int i; - /* unregister the video devices */ - while (!list_empty(&s2255_devlist)) { - list = s2255_devlist.next; - list_del(list); - } for (i = 0; i < MAX_CHANNELS; i++) { - if (-1 != dev->vdev[i]->minor) + if (-1 != dev->vdev[i]->minor) { video_unregister_device(dev->vdev[i]); - else + printk(KERN_INFO "s2255 unregistered\n"); + } else { video_device_release(dev->vdev[i]); + printk(KERN_INFO "s2255 released\n"); + } } } @@ -1781,134 +1865,123 @@ static void s2255_exit_v4l(struct s2255_dev *dev) * function again). * * Received frame structure: - * bytes 0-3: marker : 0x2255DA4AL (FRAME_MARKER) + * bytes 0-3: marker : 0x2255DA4AL (S2255_MARKER_FRAME) * bytes 4-7: channel: 0-3 * bytes 8-11: payload size: size of the frame * bytes 12-payloadsize+12: frame data */ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) { - static int dbgsync; /* = 0; */ char *pdest; u32 offset = 0; - int bsync = 0; - int btrunc = 0; + int bframe = 0; char *psrc; unsigned long copy_size; unsigned long size; s32 idx = -1; struct s2255_framei *frm; unsigned char *pdata; - unsigned long cur_size; - int bsearch = 0; - struct s2255_bufferi *buf; + dprintk(100, "buffer to user\n"); idx = dev->cur_frame[dev->cc]; - buf = &dev->buffer[dev->cc]; - frm = &buf->frame[idx]; - - if (frm->ulState == 0) { - frm->ulState = 1; - frm->cur_size = 0; - bsearch = 1; - } else if (frm->ulState == 2) { - /* system frame was not freed */ - dprintk(2, "sys frame not free. overrun ringbuf\n"); - bsearch = 1; - frm->ulState = 1; - frm->cur_size = 0; - } - - if (bsearch) { - if (*(s32 *) pipe_info->transfer_buffer != FRAME_MARKER) { - u32 jj; - if (dbgsync == 0) { - dprintk(3, "not synched, discarding all packets" - "until marker\n"); + frm = &dev->buffer[dev->cc].frame[idx]; - dbgsync++; - } - pdata = (unsigned char *)pipe_info->transfer_buffer; - for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); - jj++) { - if (*(s32 *) pdata == FRAME_MARKER) { - int cc; - dprintk(3, - "found frame marker at offset:" - " %d [%x %x]\n", jj, pdata[0], - pdata[1]); - offset = jj; - bsync = 1; - cc = *(u32 *) (pdata + sizeof(u32)); - if (cc >= MAX_CHANNELS) { - printk(KERN_ERR - "bad channel\n"); - return -EINVAL; - } - /* reverse it */ - dev->cc = G_chnmap[cc]; + if (frm->ulState == S2255_READ_IDLE) { + int jj; + unsigned int cc; + s32 *pdword; + int payload; + /* search for marker codes */ + pdata = (unsigned char *)pipe_info->transfer_buffer; + for (jj = 0; jj < (pipe_info->cur_transfer_size - 12); jj++) { + switch (*(s32 *) pdata) { + case S2255_MARKER_FRAME: + pdword = (s32 *)pdata; + dprintk(4, "found frame marker at offset:" + " %d [%x %x]\n", jj, pdata[0], + pdata[1]); + offset = jj + PREFIX_SIZE; + bframe = 1; + cc = pdword[1]; + if (cc >= MAX_CHANNELS) { + printk(KERN_ERR + "bad channel\n"); + return -EINVAL; + } + /* reverse it */ + dev->cc = G_chnmap[cc]; + payload = pdword[3]; + if (payload > dev->req_image_size[dev->cc]) { + dev->bad_payload[dev->cc]++; + /* discard the bad frame */ + return -EINVAL; + } + dev->pkt_size[dev->cc] = payload; + dev->jpg_size[dev->cc] = pdword[4]; + break; + case S2255_MARKER_RESPONSE: + pdword = (s32 *)pdata; + pdata += DEF_USB_BLOCK; + jj += DEF_USB_BLOCK; + if (pdword[1] >= MAX_CHANNELS) + break; + cc = G_chnmap[pdword[1]]; + if (!(cc >= 0 && cc < MAX_CHANNELS)) + break; + switch (pdword[2]) { + case 0x01: + /* check if channel valid */ + /* set mode ready */ + dev->setmode_ready[cc] = 1; + wake_up(&dev->wait_setmode[cc]); + dprintk(5, "setmode ready %d\n", cc); break; + case 0x10: + + dev->chn_ready |= (1 << cc); + if ((dev->chn_ready & 0x0f) != 0x0f) + break; + /* all channels ready */ + printk(KERN_INFO "s2255: fw loaded\n"); + atomic_set(&dev->fw_data->fw_state, + S2255_FW_SUCCESS); + wake_up(&dev->fw_data->wait_fw); + break; + default: + printk(KERN_INFO "s2255 unknwn resp\n"); } + default: pdata++; + break; } - if (bsync == 0) - return -EINVAL; - } else { - u32 *pword; - u32 payload; - int cc; - dbgsync = 0; - bsync = 1; - pword = (u32 *) pipe_info->transfer_buffer; - cc = pword[1]; - - if (cc >= MAX_CHANNELS) { - printk("invalid channel found. " - "throwing out data!\n"); - return -EINVAL; - } - dev->cc = G_chnmap[cc]; - payload = pword[2]; - if (payload != dev->req_image_size[dev->cc]) { - dprintk(1, "[%d][%d]unexpected payload: %d" - "required: %lu \n", cc, dev->cc, - payload, dev->req_image_size[dev->cc]); - dev->bad_payload[dev->cc]++; - /* discard the bad frame */ - return -EINVAL; - } - - } - } - /* search done. now find out if should be acquiring - on this channel */ - if (!dev->b_acquire[dev->cc]) { - frm->ulState = 0; - return -EINVAL; + if (bframe) + break; + } /* for */ + if (!bframe) + return -EINVAL; } + idx = dev->cur_frame[dev->cc]; frm = &dev->buffer[dev->cc].frame[idx]; - if (frm->ulState == 0) { - frm->ulState = 1; - frm->cur_size = 0; - } else if (frm->ulState == 2) { - /* system frame ring buffer overrun */ - dprintk(2, "sys frame overrun. overwriting frame %d %d\n", - dev->cc, idx); - frm->ulState = 1; - frm->cur_size = 0; + /* search done. now find out if should be acquiring on this channel */ + if (!dev->b_acquire[dev->cc]) { + /* we found a frame, but this channel is turned off */ + frm->ulState = S2255_READ_IDLE; + return -EINVAL; } - if (bsync) { - /* skip the marker 512 bytes (and offset if out of sync) */ - psrc = (u8 *)pipe_info->transfer_buffer + offset + PREFIX_SIZE; - } else { - psrc = (u8 *)pipe_info->transfer_buffer; + if (frm->ulState == S2255_READ_IDLE) { + frm->ulState = S2255_READ_FRAME; + frm->cur_size = 0; } + /* skip the marker 512 bytes (and offset if out of sync) */ + psrc = (u8 *)pipe_info->transfer_buffer + offset; + + if (frm->lpvbits == NULL) { dprintk(1, "s2255 frame buffer == NULL.%p %p %d %d", frm, dev, dev->cc, idx); @@ -1917,33 +1990,20 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) pdest = frm->lpvbits + frm->cur_size; - if (bsync) { - copy_size = - (pipe_info->cur_transfer_size - offset) - PREFIX_SIZE; - if (copy_size > pipe_info->cur_transfer_size) { - printk("invalid copy size, overflow!\n"); - return -ENOMEM; - } - } else { - copy_size = pipe_info->cur_transfer_size; - } + copy_size = (pipe_info->cur_transfer_size - offset); - cur_size = frm->cur_size; - size = dev->req_image_size[dev->cc]; + size = dev->pkt_size[dev->cc] - PREFIX_SIZE; - if ((copy_size + cur_size) > size) { - copy_size = size - cur_size; - btrunc = 1; - } + /* sanity check on pdest */ + if ((copy_size + frm->cur_size) < dev->req_image_size[dev->cc]) + memcpy(pdest, psrc, copy_size); - memcpy(pdest, psrc, copy_size); - cur_size += copy_size; frm->cur_size += copy_size; - dprintk(50, "cur_size size %lu size %lu \n", cur_size, size); + dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size); + + if (frm->cur_size >= size) { - if (cur_size >= (size - PREFIX_SIZE)) { u32 cc = dev->cc; - frm->ulState = 2; dprintk(2, "****************[%d]Buffer[%d]full*************\n", cc, idx); dev->last_frame[cc] = dev->cur_frame[cc]; @@ -1952,16 +2012,13 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info) if ((dev->cur_frame[cc] == SYS_FRAMES) || (dev->cur_frame[cc] == dev->buffer[cc].dwFrames)) dev->cur_frame[cc] = 0; - - /* signal the semaphore for this channel */ + /* frame ready */ if (dev->b_acquire[cc]) - s2255_got_frame(dev, cc); + s2255_got_frame(dev, cc, dev->jpg_size[cc]); dev->frame_count[cc]++; - } - /* frame was truncated */ - if (btrunc) { - /* return more data to process */ - return EAGAIN; + frm->ulState = S2255_READ_IDLE; + frm->cur_size = 0; + } /* done successfully */ return 0; @@ -1980,8 +2037,8 @@ static void s2255_read_video_callback(struct s2255_dev *dev, } /* otherwise copy to the system buffers */ res = save_frame(dev, pipe_info); - if (res == EAGAIN) - save_frame(dev, pipe_info); + if (res != 0) + dprintk(4, "s2255: read callback failed\n"); dprintk(50, "callback read video done\n"); return; @@ -2101,11 +2158,9 @@ static int s2255_board_init(struct s2255_dev *dev) memset(pipe, 0, sizeof(*pipe)); pipe->dev = dev; - pipe->cur_transfer_size = DEFAULT_PIPE_USBBLOCK; - pipe->max_transfer_size = MAX_PIPE_USBBLOCK; + pipe->cur_transfer_size = S2255_USB_XFER_SIZE; + pipe->max_transfer_size = S2255_USB_XFER_SIZE; - if (pipe->cur_transfer_size > pipe->max_transfer_size) - pipe->cur_transfer_size = pipe->max_transfer_size; pipe->transfer_buffer = kzalloc(pipe->max_transfer_size, GFP_KERNEL); if (pipe->transfer_buffer == NULL) { @@ -2125,6 +2180,7 @@ static int s2255_board_init(struct s2255_dev *dev) for (j = 0; j < MAX_CHANNELS; j++) { dev->b_acquire[j] = 0; dev->mode[j] = mode_def; + dev->jc[j].quality = S2255_DEF_JPEG_QUAL; dev->cur_fmt[j] = &formats[0]; dev->mode[j].restart = 1; dev->req_image_size[j] = get_transfer_size(&mode_def); @@ -2329,7 +2385,7 @@ static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn) kfree(buffer); dev->b_acquire[chn] = 0; - return 0; + return res; } static void s2255_stop_readpipe(struct s2255_dev *dev) @@ -2365,8 +2421,10 @@ static void s2255_stop_readpipe(struct s2255_dev *dev) return; } -static void s2255_fwload_start(struct s2255_dev *dev) +static void s2255_fwload_start(struct s2255_dev *dev, int reset) { + if (reset) + s2255_reset_dsppower(dev); dev->fw_data->fw_size = dev->fw_data->fw->size; atomic_set(&dev->fw_data->fw_state, S2255_FW_NOTLOADED); memcpy(dev->fw_data->pfw_data, @@ -2389,6 +2447,8 @@ static int s2255_probe(struct usb_interface *interface, struct usb_endpoint_descriptor *endpoint; int i; int retval = -ENOMEM; + __le32 *pdata; + int fw_size; dprintk(2, "s2255: probe\n"); @@ -2443,6 +2503,8 @@ static int s2255_probe(struct usb_interface *interface, dev->timer.data = (unsigned long)dev->fw_data; init_waitqueue_head(&dev->fw_data->wait_fw); + for (i = 0; i < MAX_CHANNELS; i++) + init_waitqueue_head(&dev->wait_setmode[i]); dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -2462,16 +2524,30 @@ static int s2255_probe(struct usb_interface *interface, printk(KERN_ERR "sensoray 2255 failed to get firmware\n"); goto error; } + /* check the firmware is valid */ + fw_size = dev->fw_data->fw->size; + pdata = (__le32 *) &dev->fw_data->fw->data[fw_size - 8]; + if (*pdata != S2255_FW_MARKER) { + printk(KERN_INFO "Firmware invalid.\n"); + retval = -ENODEV; + goto error; + } else { + /* make sure firmware is the latest */ + __le32 *pRel; + pRel = (__le32 *) &dev->fw_data->fw->data[fw_size - 4]; + printk(KERN_INFO "s2255 dsp fw version %x\n", *pRel); + } /* loads v4l specific */ s2255_probe_v4l(dev); + usb_reset_device(dev->udev); /* load 2255 board specific */ s2255_board_init(dev); dprintk(4, "before probe done %p\n", dev); spin_lock_init(&dev->slock); - s2255_fwload_start(dev); + s2255_fwload_start(dev, 0); dev_info(&interface->dev, "Sensoray 2255 detected\n"); return 0; error: @@ -2482,14 +2558,30 @@ error: static void s2255_disconnect(struct usb_interface *interface) { struct s2255_dev *dev = NULL; + int i; dprintk(1, "s2255: disconnect interface %p\n", interface); dev = usb_get_intfdata(interface); + + /* + * wake up any of the timers to allow open_lock to be + * acquired sooner + */ + atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING); + wake_up(&dev->fw_data->wait_fw); + for (i = 0; i < MAX_CHANNELS; i++) { + dev->setmode_ready[i] = 1; + wake_up(&dev->wait_setmode[i]); + } + + mutex_lock(&dev->open_lock); + usb_set_intfdata(interface, NULL); + mutex_unlock(&dev->open_lock); + if (dev) { kref_put(&dev->kref, s2255_destroy); dprintk(1, "s2255drv: disconnect\n"); dev_info(&interface->dev, "s2255usb now disconnected\n"); } - usb_set_intfdata(interface, NULL); } static struct usb_driver s2255_driver = { diff --git a/linux/drivers/media/video/saa5246a.c b/linux/drivers/media/video/saa5246a.c index 1bfc49822..c65fba519 100644 --- a/linux/drivers/media/video/saa5246a.c +++ b/linux/drivers/media/video/saa5246a.c @@ -62,6 +62,7 @@ struct saa5246a_device u8 pgbuf[NUM_DAUS][VTX_VIRTUALSIZE]; int is_searching[NUM_DAUS]; struct i2c_client *client; + unsigned long in_use; struct mutex lock; }; @@ -117,7 +118,7 @@ static int saa5246a_attach(struct i2c_adapter *adap, int addr, int kind) memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0])); t->is_searching[pgbuf] = false; } - vd->priv=t; + video_set_drvdata(vd, t); /* @@ -149,9 +150,10 @@ static int saa5246a_probe(struct i2c_adapter *adap) static int saa5246a_detach(struct i2c_client *client) { struct video_device *vd = i2c_get_clientdata(client); + i2c_detach_client(client); video_unregister_device(vd); - kfree(vd->priv); + kfree(video_get_drvdata(vd)); kfree(client); return 0; } @@ -581,8 +583,8 @@ static inline int saa5246a_stop_dau(struct saa5246a_device *t, static int do_saa5246a_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { - struct video_device *vd = video_devdata(file); - struct saa5246a_device *t=vd->priv; + struct saa5246a_device *t = video_drvdata(file); + switch(cmd) { case VTXIOCGETINFO: @@ -722,8 +724,7 @@ static inline unsigned int vtx_fix_command(unsigned int cmd) static int saa5246a_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct video_device *vd = video_devdata(file); - struct saa5246a_device *t = vd->priv; + struct saa5246a_device *t = video_drvdata(file); int err; cmd = vtx_fix_command(cmd); @@ -735,24 +736,15 @@ static int saa5246a_ioctl(struct inode *inode, struct file *file, static int saa5246a_open(struct inode *inode, struct file *file) { - struct video_device *vd = video_devdata(file); - struct saa5246a_device *t = vd->priv; - int err; + struct saa5246a_device *t = video_drvdata(file); - lock_kernel(); - err = video_exclusive_open(inode,file); - if (err < 0) { - unlock_kernel(); - return err; - } + if (t->client == NULL) + return -ENODEV; - if (t->client==NULL) { - err = -ENODEV; - goto fail; - } + if (test_and_set_bit(0, &t->in_use)) + return -EBUSY; if (i2c_senddata(t, SAA5246A_REGISTER_R0, - R0_SELECT_R11 | R0_PLL_TIME_CONSTANT_LONG | R0_ENABLE_nODD_EVEN_OUTPUT | @@ -778,23 +770,15 @@ static int saa5246a_open(struct inode *inode, struct file *file) COMMAND_END)) { - err = -EIO; - goto fail; + clear_bit(0, &t->in_use); + return -EIO; } - unlock_kernel(); - return 0; - -fail: - video_exclusive_release(inode,file); - unlock_kernel(); - return err; } static int saa5246a_release(struct inode *inode, struct file *file) { - struct video_device *vd = video_devdata(file); - struct saa5246a_device *t = vd->priv; + struct saa5246a_device *t = video_drvdata(file); /* Stop all acquisition circuits. */ i2c_senddata(t, SAA5246A_REGISTER_R1, @@ -807,7 +791,7 @@ static int saa5246a_release(struct inode *inode, struct file *file) R1_VCS_TO_SCS, COMMAND_END); - video_exclusive_release(inode,file); + clear_bit(0, &t->in_use); return 0; } diff --git a/linux/drivers/media/video/saa5249.c b/linux/drivers/media/video/saa5249.c index 81d341a80..398089510 100644 --- a/linux/drivers/media/video/saa5249.c +++ b/linux/drivers/media/video/saa5249.c @@ -111,6 +111,7 @@ struct saa5249_device int disp_mode; int virtual_mode; struct i2c_client *client; + unsigned long in_use; struct mutex lock; }; @@ -186,7 +187,7 @@ static int saa5249_attach(struct i2c_adapter *adap, int addr, int kind) t->vdau[pgbuf].stopped = true; t->is_searching[pgbuf] = false; } - vd->priv=t; + video_set_drvdata(vd, t); /* @@ -221,7 +222,7 @@ static int saa5249_detach(struct i2c_client *client) struct video_device *vd = i2c_get_clientdata(client); i2c_detach_client(client); video_unregister_device(vd); - kfree(vd->priv); + kfree(video_get_drvdata(vd)); kfree(vd); kfree(client); return 0; @@ -319,8 +320,7 @@ static int do_saa5249_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { static int virtual_mode = false; - struct video_device *vd = video_devdata(file); - struct saa5249_device *t=vd->priv; + struct saa5249_device *t = video_drvdata(file); switch(cmd) { @@ -618,8 +618,7 @@ static inline unsigned int vtx_fix_command(unsigned int cmd) static int saa5249_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct video_device *vd = video_devdata(file); - struct saa5249_device *t=vd->priv; + struct saa5249_device *t = video_drvdata(file); int err; cmd = vtx_fix_command(cmd); @@ -631,35 +630,27 @@ static int saa5249_ioctl(struct inode *inode, struct file *file, static int saa5249_open(struct inode *inode, struct file *file) { - struct video_device *vd = video_devdata(file); - struct saa5249_device *t=vd->priv; - int err,pgbuf; - - lock_kernel(); - err = video_exclusive_open(inode,file); - if (err < 0) { - unlock_kernel(); - return err; - } + struct saa5249_device *t = video_drvdata(file); + int pgbuf; - if (t->client==NULL) { - err = -ENODEV; - goto fail; - } + if (t->client == NULL) + return -ENODEV; - if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */ - /* Turn off parity checks (we do this ourselves) */ - i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) || - /* Display TV-picture, no virtual rows */ - i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1)) /* Set display to page 4 */ + if (test_and_set_bit(0, &t->in_use)) + return -EBUSY; + if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */ + /* Turn off parity checks (we do this ourselves) */ + i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) || + /* Display TV-picture, no virtual rows */ + i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1)) + /* Set display to page 4 */ { - err = -EIO; - goto fail; + clear_bit(0, &t->in_use); + return -EIO; } - for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) - { + for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) { memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf)); memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs)); memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat)); @@ -669,24 +660,18 @@ 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; } static int saa5249_release(struct inode *inode, struct file *file) { - struct video_device *vd = video_devdata(file); - struct saa5249_device *t=vd->priv; + struct saa5249_device *t = video_drvdata(file); + i2c_senddata(t, 1, 0x20, -1); /* Turn off CCT */ i2c_senddata(t, 5, 3, 3, -1); /* Turn off TV-display */ - video_exclusive_release(inode,file); + clear_bit(0, &t->in_use); return 0; } @@ -720,6 +705,7 @@ static struct video_device saa_template = { .name = IF_NAME, .fops = &saa_fops, + .release = video_device_release, }; MODULE_LICENSE("GPL"); diff --git a/linux/drivers/media/video/saa7115.c b/linux/drivers/media/video/saa7115.c index 5488679ed..e2c68d8ca 100644 --- a/linux/drivers/media/video/saa7115.c +++ b/linux/drivers/media/video/saa7115.c @@ -1498,10 +1498,9 @@ static int saa7115_probe(struct i2c_client *client, client->addr << 1, client->adapter->name); state = kzalloc(sizeof(struct saa711x_state), GFP_KERNEL); - i2c_set_clientdata(client, state); - if (state == NULL) { + if (state == NULL) return -ENOMEM; - } + i2c_set_clientdata(client, state); state->input = -1; state->output = SAA7115_IPORT_ON; state->enable = 1; diff --git a/linux/drivers/media/video/saa7134/saa6752hs.c b/linux/drivers/media/video/saa7134/saa6752hs.c index 011fc19f6..6c97d4ab4 100644 --- a/linux/drivers/media/video/saa7134/saa6752hs.c +++ b/linux/drivers/media/video/saa7134/saa6752hs.c @@ -654,7 +654,7 @@ static int saa6752hs_qmenu(struct saa6752hs_state *h, return v4l2_ctrl_query_menu(qmenu, &qctrl, NULL); } -static int saa6752hs_init(struct i2c_client* client) +static int saa6752hs_init(struct i2c_client *client, u32 leading_null_bytes) { unsigned char buf[9], buf2[4]; struct saa6752hs_state *h; @@ -706,6 +706,12 @@ static int saa6752hs_init(struct i2c_client* client) buf[1] = 0x05; i2c_master_send(client,buf,2); + /* Set leading null byte for TS */ + buf[0] = 0xF6; + buf[1] = (leading_null_bytes >> 8) & 0xff; + buf[2] = leading_null_bytes & 0xff; + i2c_master_send(client, buf, 3); + /* compute PAT */ memcpy(localPAT, PAT, sizeof(PAT)); localPAT[17] = 0xe0 | ((h->params.ts_pid_pmt >> 8) & 0x0f); @@ -813,14 +819,13 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) int i; switch (cmd) { + case VIDIOC_INT_INIT: + /* apply settings and start encoder */ + saa6752hs_init(client, *(u32 *)arg); + break; case VIDIOC_S_EXT_CTRLS: if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG) return -EINVAL; - if (ctrls->count == 0) { - /* apply settings and start encoder */ - saa6752hs_init(client); - break; - } /* fall through */ case VIDIOC_TRY_EXT_CTRLS: case VIDIOC_G_EXT_CTRLS: diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c index 117f33946..ce8bcc967 100644 --- a/linux/drivers/media/video/saa7134/saa7134-core.c +++ b/linux/drivers/media/video/saa7134/saa7134-core.c @@ -465,9 +465,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) /* TS capture -- dma 5 */ if (dev->ts_q.curr) { ctrl |= SAA7134_MAIN_CTRL_TE5; - irq |= SAA7134_IRQ1_INTE_RA2_3 | - SAA7134_IRQ1_INTE_RA2_2 | - SAA7134_IRQ1_INTE_RA2_1 | + irq |= SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0; } diff --git a/linux/drivers/media/video/saa7134/saa7134-empress.c b/linux/drivers/media/video/saa7134/saa7134-empress.c index 5225ed6b8..1451fdf99 100644 --- a/linux/drivers/media/video/saa7134/saa7134-empress.c +++ b/linux/drivers/media/video/saa7134/saa7134-empress.c @@ -64,10 +64,19 @@ static void ts_reset_encoder(struct saa7134_dev* dev) static int ts_init_encoder(struct saa7134_dev* dev) { - struct v4l2_ext_controls ctrls = { V4L2_CTRL_CLASS_MPEG, 0 }; - + u32 leading_null_bytes = 0; + + /* If more cards start to need this, then this + should probably be added to the card definitions. */ + switch (dev->board) { + case SAA7134_BOARD_BEHOLD_M6: + case SAA7134_BOARD_BEHOLD_M63: + case SAA7134_BOARD_BEHOLD_M6_EXTRA: + leading_null_bytes = 1; + break; + } ts_reset_encoder(dev); - saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, &ctrls); + saa7134_i2c_call_clients(dev, VIDIOC_INT_INIT, &leading_null_bytes); dev->empress_started = 1; return 0; } diff --git a/linux/drivers/media/video/saa7134/saa7134-ts.c b/linux/drivers/media/video/saa7134/saa7134-ts.c index eae72fd60..ef55a59f0 100644 --- a/linux/drivers/media/video/saa7134/saa7134-ts.c +++ b/linux/drivers/media/video/saa7134/saa7134-ts.c @@ -66,11 +66,29 @@ static int buffer_activate(struct saa7134_dev *dev, saa7134_set_dmabits(dev); mod_timer(&dev->ts_q.timeout, jiffies+BUFFER_TIMEOUT); + + if (dev->ts_state == SAA7134_TS_BUFF_DONE) { + /* Clear TS cache */ + dev->buff_cnt = 0; + saa_writeb(SAA7134_TS_SERIAL1, 0x00); + saa_writeb(SAA7134_TS_SERIAL1, 0x03); + saa_writeb(SAA7134_TS_SERIAL1, 0x00); + saa_writeb(SAA7134_TS_SERIAL1, 0x01); + + /* TS clock non-inverted */ + saa_writeb(SAA7134_TS_SERIAL1, 0x00); + + /* Start TS stream */ + saa_writeb(SAA7134_TS_SERIAL0, 0x40); + saa_writeb(SAA7134_TS_PARALLEL, 0xEC); + dev->ts_state = SAA7134_TS_STARTED; + } + return 0; } static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, - enum v4l2_field field) + enum v4l2_field field) { struct saa7134_dev *dev = q->priv_data; struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); @@ -110,16 +128,22 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, goto oops; } - /* dma: setup channel 5 (= TS) */ - control = SAA7134_RS_CONTROL_BURST_16 | - SAA7134_RS_CONTROL_ME | - (buf->pt->dma >> 12); - - saa_writeb(SAA7134_TS_DMA0, ((lines-1)&0xff)); - saa_writeb(SAA7134_TS_DMA1, (((lines-1)>>8)&0xff)); - saa_writeb(SAA7134_TS_DMA2, ((((lines-1)>>16)&0x3f) | 0x00)); /* TSNOPIT=0, TSCOLAP=0 */ - saa_writel(SAA7134_RS_PITCH(5),TS_PACKET_SIZE); - saa_writel(SAA7134_RS_CONTROL(5),control); + dev->buff_cnt++; + + if (dev->buff_cnt == dev->ts.nr_bufs) { + dev->ts_state = SAA7134_TS_BUFF_DONE; + /* dma: setup channel 5 (= TS) */ + control = SAA7134_RS_CONTROL_BURST_16 | + SAA7134_RS_CONTROL_ME | + (buf->pt->dma >> 12); + + saa_writeb(SAA7134_TS_DMA0, (lines - 1) & 0xff); + saa_writeb(SAA7134_TS_DMA1, ((lines - 1) >> 8) & 0xff); + /* TSNOPIT=0, TSCOLAP=0 */ + saa_writeb(SAA7134_TS_DMA2, (((lines - 1) >> 16) & 0x3f) | 0x00); + saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE); + saa_writel(SAA7134_RS_CONTROL(5), control); + } buf->vb.state = VIDEOBUF_PREPARED; buf->activate = buffer_activate; @@ -140,6 +164,8 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) if (0 == *count) *count = dev->ts.nr_bufs; *count = saa7134_buffer_count(*size,*count); + dev->buff_cnt = 0; + dev->ts_state = SAA7134_TS_STOPPED; return 0; } @@ -154,7 +180,13 @@ static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb) static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb) { struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb); + struct saa7134_dev *dev = q->priv_data; + if (dev->ts_state == SAA7134_TS_STARTED) { + /* Stop TS transport */ + saa_writeb(SAA7134_TS_PARALLEL, 0x6c); + dev->ts_state = SAA7134_TS_STOPPED; + } saa7134_dma_free(q,buf); } @@ -182,7 +214,7 @@ int saa7134_ts_init_hw(struct saa7134_dev *dev) /* deactivate TS softreset */ saa_writeb(SAA7134_TS_SERIAL1, 0x00); /* TSSOP high active, TSVAL high active, TSLOCK ignored */ - saa_writeb(SAA7134_TS_PARALLEL, 0xec); + saa_writeb(SAA7134_TS_PARALLEL, 0x6c); saa_writeb(SAA7134_TS_PARALLEL_SERIAL, (TS_PACKET_SIZE-1)); saa_writeb(SAA7134_TS_DMA0, ((dev->ts.nr_packets-1)&0xff)); saa_writeb(SAA7134_TS_DMA1, (((dev->ts.nr_packets-1)>>8)&0xff)); diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h index e3ad9d9e7..55aa60f52 100644 --- a/linux/drivers/media/video/saa7134/saa7134.h +++ b/linux/drivers/media/video/saa7134/saa7134.h @@ -467,6 +467,12 @@ struct saa7134_mpeg_ops { void (*signal_change)(struct saa7134_dev *dev); }; +enum saa7134_ts_status { + SAA7134_TS_STOPPED, + SAA7134_TS_BUFF_DONE, + SAA7134_TS_STARTED, +}; + /* global device status */ struct saa7134_dev { struct list_head devlist; @@ -560,6 +566,8 @@ struct saa7134_dev { /* SAA7134_MPEG_* */ struct saa7134_ts ts; struct saa7134_dmaqueue ts_q; + enum saa7134_ts_status ts_state; + unsigned int buff_cnt; struct saa7134_mpeg_ops *mops; struct i2c_client *mpeg_i2c_client; diff --git a/linux/drivers/media/video/se401.c b/linux/drivers/media/video/se401.c index 04897413d..4b55b7dd7 100644 --- a/linux/drivers/media/video/se401.c +++ b/linux/drivers/media/video/se401.c @@ -1244,6 +1244,7 @@ static const struct file_operations se401_fops = { static struct video_device se401_template = { .name = "se401 USB camera", .fops = &se401_fops, + .release = video_device_release_empty, }; @@ -1409,7 +1410,7 @@ static int se401_probe(struct usb_interface *intf, mutex_init(&se401->lock); wmb(); - if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + if (video_register_device(&se401->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { kfree(se401); err("video_register_device failed"); return -EIO; diff --git a/linux/drivers/media/video/sn9c102/sn9c102_core.c b/linux/drivers/media/video/sn9c102/sn9c102_core.c index e92e79da3..fd867dadf 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_core.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_core.c @@ -116,6 +116,26 @@ MODULE_PARM_DESC(debug, "\n"); #endif +/* + Add the probe entries to this table. Be sure to add the entry in the right + place, since, on failure, the next probing routine is called according to + the order of the list below, from top to bottom. +*/ +static int (*sn9c102_sensor_table[])(struct sn9c102_device *) = { + &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ + &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ + &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ + &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ + &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */ + &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ + &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ + &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ + &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ + &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ + &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */ + &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ +}; + /*****************************************************************************/ static u32 @@ -1750,7 +1770,7 @@ static int sn9c102_open(struct inode* inode, struct file* filp) if (!down_read_trylock(&sn9c102_dev_lock)) return -ERESTARTSYS; - cam = video_get_drvdata(video_devdata(filp)); + cam = video_drvdata(filp); if (wait_for_completion_interruptible(&cam->probe)) { up_read(&sn9c102_dev_lock); @@ -1847,7 +1867,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp) down_write(&sn9c102_dev_lock); - cam = video_get_drvdata(video_devdata(filp)); + cam = video_drvdata(filp); sn9c102_stop_transfer(cam); sn9c102_release_buffers(cam); @@ -1867,7 +1887,7 @@ static int sn9c102_release(struct inode* inode, struct file* filp) static ssize_t sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) { - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + struct sn9c102_device *cam = video_drvdata(filp); struct sn9c102_frame_t* f, * i; unsigned long lock_flags; long timeout; @@ -1991,7 +2011,7 @@ exit: static unsigned int sn9c102_poll(struct file *filp, poll_table *wait) { - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + struct sn9c102_device *cam = video_drvdata(filp); struct sn9c102_frame_t* f; unsigned long lock_flags; unsigned int mask = 0; @@ -2067,7 +2087,7 @@ static struct vm_operations_struct sn9c102_vm_ops = { static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) { - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + struct sn9c102_device *cam = video_drvdata(filp); unsigned long size = vma->vm_end - vma->vm_start, start = vma->vm_start; void *pos; @@ -3079,7 +3099,7 @@ sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg) static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, unsigned int cmd, void __user * arg) { - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + struct sn9c102_device *cam = video_drvdata(filp); switch (cmd) { @@ -3183,7 +3203,7 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp, static int sn9c102_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg) { - struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); + struct sn9c102_device *cam = video_drvdata(filp); int err = 0; if (mutex_lock_interruptible(&cam->fileop_mutex)) @@ -3316,6 +3336,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->fops = &sn9c102_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; + cam->v4ldev->parent = &udev->dev; init_completion(&cam->probe); diff --git a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h index 6ff489baa..e23734f6d 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_devtable.h +++ b/linux/drivers/media/video/sn9c102/sn9c102_devtable.h @@ -40,11 +40,14 @@ struct sn9c102_device; static const struct usb_device_id sn9c102_id_table[] = { /* SN9C101 and SN9C102 */ +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */ { SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), }, @@ -53,29 +56,33 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), }, - { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */ { SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), }, { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* SN9C103 */ { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */ { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */ +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, - { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */ +/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5130 */ { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), }, +#if !defined CONFIG_USB_GSPCA && !defined CONFIG_USB_GSPCA_MODULE { SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), }, +#endif { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, @@ -105,7 +112,7 @@ static const struct usb_device_id sn9c102_id_table[] = { { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), }, - { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, +/* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */ { SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), }, { SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), }, @@ -133,24 +140,4 @@ extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam); extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam); extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam); -/* - Add the above entries to this table. Be sure to add the entry in the right - place, since, on failure, the next probing routine is called according to - the order of the list below, from top to bottom. -*/ -static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { - &sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ - &sn9c102_probe_hv7131r, /* strong detection based on SENSOR ids */ - &sn9c102_probe_mi0343, /* strong detection based on SENSOR ids */ - &sn9c102_probe_mi0360, /* strong detection based on SENSOR ids */ - &sn9c102_probe_mt9v111, /* strong detection based on SENSOR ids */ - &sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ - &sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ - &sn9c102_probe_ov7630, /* strong detection based on SENSOR ids */ - &sn9c102_probe_ov7660, /* strong detection based on SENSOR ids */ - &sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ - &sn9c102_probe_tas5110d, /* detection based on USB pid/vid */ - &sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ -}; - #endif /* _SN9C102_DEVTABLE_H_ */ diff --git a/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c b/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c index eaf9ad0dc..db2434948 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_hv7131d.c @@ -20,6 +20,7 @@ ***************************************************************************/ #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int hv7131d_init(struct sn9c102_device* cam) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_hv7131r.c b/linux/drivers/media/video/sn9c102/sn9c102_hv7131r.c index 0fc401223..4295887ff 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_hv7131r.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_hv7131r.c @@ -20,6 +20,7 @@ ***************************************************************************/ #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int hv7131r_init(struct sn9c102_device* cam) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c b/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c index 00b134ca0..1f5b09bec 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_mi0343.c @@ -20,6 +20,7 @@ ***************************************************************************/ #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int mi0343_init(struct sn9c102_device* cam) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_mi0360.c b/linux/drivers/media/video/sn9c102/sn9c102_mi0360.c index f8d81d82e..d973fc197 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_mi0360.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_mi0360.c @@ -20,6 +20,7 @@ ***************************************************************************/ #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int mi0360_init(struct sn9c102_device* cam) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_mt9v111.c b/linux/drivers/media/video/sn9c102/sn9c102_mt9v111.c index 3b98ac3bb..95986eb49 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_mt9v111.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_mt9v111.c @@ -20,6 +20,7 @@ ***************************************************************************/ #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int mt9v111_init(struct sn9c102_device *cam) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c b/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c index e4856fd77..803712c29 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_ov7630.c @@ -20,6 +20,7 @@ ***************************************************************************/ #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int ov7630_init(struct sn9c102_device* cam) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c b/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c index 8aae416ba..7977795d3 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_ov7660.c @@ -20,6 +20,7 @@ ***************************************************************************/ #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int ov7660_init(struct sn9c102_device* cam) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c b/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c index 360f2a848..81cd969c1 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_pas106b.c @@ -21,6 +21,7 @@ #include <linux/delay.h> #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int pas106b_init(struct sn9c102_device* cam) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c index ca4a1506e..2782f94cf 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_pas202bcb.c @@ -26,6 +26,7 @@ #include <linux/delay.h> #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int pas202bcb_init(struct sn9c102_device* cam) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c b/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c index e7d2de2ba..04cdfdde8 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_tas5110c1b.c @@ -20,6 +20,7 @@ ***************************************************************************/ #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int tas5110c1b_init(struct sn9c102_device* cam) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_tas5110d.c b/linux/drivers/media/video/sn9c102/sn9c102_tas5110d.c index d32fdbccd..9372e6f9f 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_tas5110d.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_tas5110d.c @@ -20,6 +20,7 @@ ***************************************************************************/ #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int tas5110d_init(struct sn9c102_device* cam) diff --git a/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c b/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c index 56fb1d575..a30bbc438 100644 --- a/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c +++ b/linux/drivers/media/video/sn9c102/sn9c102_tas5130d1b.c @@ -20,6 +20,7 @@ ***************************************************************************/ #include "sn9c102_sensor.h" +#include "sn9c102_devtable.h" static int tas5130d1b_init(struct sn9c102_device* cam) diff --git a/linux/drivers/media/video/stk-webcam.c b/linux/drivers/media/video/stk-webcam.c index c6660b363..055e92549 100644 --- a/linux/drivers/media/video/stk-webcam.c +++ b/linux/drivers/media/video/stk-webcam.c @@ -73,7 +73,7 @@ static void stk_camera_cleanup(struct kref *kref) STK_INFO("Syntek USB2.0 Camera release resources" " video device /dev/video%d\n", dev->vdev.minor); video_unregister_device(&dev->vdev); - dev->vdev.priv = NULL; + video_set_drvdata(&dev->vdev, NULL); if (dev->sio_bufs != NULL || dev->isobufs != NULL) STK_ERROR("We are leaking memory\n"); @@ -1380,7 +1380,7 @@ static int stk_register_video_device(struct stk_camera *dev) dev->vdev = stk_v4l_data; dev->vdev.debug = debug; dev->vdev.parent = &dev->interface->dev; - dev->vdev.priv = dev; + video_set_drvdata(&dev->vdev, dev); err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); if (err) STK_ERROR("v4l registration failed\n"); diff --git a/linux/drivers/media/video/stradis.c b/linux/drivers/media/video/stradis.c index a081307c7..0e2b246c7 100644 --- a/linux/drivers/media/video/stradis.c +++ b/linux/drivers/media/video/stradis.c @@ -1930,6 +1930,7 @@ static struct video_device saa_template = { .name = "SAA7146A", .fops = &saa_fops, .minor = -1, + .release = video_device_release_empty, }; static int __devinit configure_saa7146(struct pci_dev *pdev, int num) diff --git a/linux/drivers/media/video/stv680.c b/linux/drivers/media/video/stv680.c index de32a5266..8df48a547 100644 --- a/linux/drivers/media/video/stv680.c +++ b/linux/drivers/media/video/stv680.c @@ -1469,7 +1469,7 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id mutex_init (&stv680->lock); wmb (); - if (video_register_device (stv680->vdev, VFL_TYPE_GRABBER, video_nr) == -1) { + if (video_register_device(stv680->vdev, VFL_TYPE_GRABBER, video_nr) < 0) { PDEBUG (0, "STV(e): video_register_device failed"); retval = -EIO; goto error_vdev; diff --git a/linux/drivers/media/video/usbvideo/ibmcam.c b/linux/drivers/media/video/usbvideo/ibmcam.c index 1afbcc147..697e74a24 100644 --- a/linux/drivers/media/video/usbvideo/ibmcam.c +++ b/linux/drivers/media/video/usbvideo/ibmcam.c @@ -736,12 +736,12 @@ static enum ParseState ibmcam_model2_320x240_parse_lines( * make black color and quit the horizontal scanning loop. */ if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) { - const int j = i * V4L_BYTES_PER_PIXEL; + const int offset = i * V4L_BYTES_PER_PIXEL; #if USES_IBMCAM_PUTPIXEL /* Refresh 'f' because we don't use it much with PUTPIXEL */ - f = frame->data + (v4l_linesize * frame->curline) + j; + f = frame->data + (v4l_linesize * frame->curline) + offset; #endif - memset(f, 0, v4l_linesize - j); + memset(f, 0, v4l_linesize - offset); break; } diff --git a/linux/drivers/media/video/usbvideo/usbvideo.c b/linux/drivers/media/video/usbvideo/usbvideo.c index 4b28a6dfb..2e29d95b6 100644 --- a/linux/drivers/media/video/usbvideo/usbvideo.c +++ b/linux/drivers/media/video/usbvideo/usbvideo.c @@ -1006,10 +1006,6 @@ 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 */ @@ -1043,7 +1039,7 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd) return -EINVAL; } uvd->vdev.parent = &uvd->dev->dev; - uvd->vdev.release = usbvideo_dummy_release; + uvd->vdev.release = video_device_release_empty; 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 e7330fe4f..bad26ccf8 100644 --- a/linux/drivers/media/video/usbvideo/vicam.c +++ b/linux/drivers/media/video/usbvideo/vicam.c @@ -782,9 +782,8 @@ vicam_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, unsign static int vicam_open(struct inode *inode, struct file *file) { - struct video_device *dev = video_devdata(file); - struct vicam_camera *cam = - (struct vicam_camera *) dev->priv; + struct vicam_camera *cam = video_drvdata(file); + DBG("open\n"); if (!cam) { @@ -1111,6 +1110,7 @@ static struct video_device vicam_template = { .name = "ViCam-based USB Camera", .fops = &vicam_fops, .minor = -1, + .release = video_device_release_empty, }; /* table of devices that work with this driver */ @@ -1175,14 +1175,13 @@ vicam_probe( struct usb_interface *intf, const struct usb_device_id *id) mutex_init(&cam->cam_lock); - memcpy(&cam->vdev, &vicam_template, - sizeof (vicam_template)); - cam->vdev.priv = cam; // sort of a reverse mapping for those functions that get vdev only + memcpy(&cam->vdev, &vicam_template, sizeof(vicam_template)); + video_set_drvdata(&cam->vdev, cam); cam->udev = dev; cam->bulkEndpoint = bulkEndpoint; - if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) == -1) { + if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) { kfree(cam); printk(KERN_WARNING "video_register_device failed\n"); return -EIO; diff --git a/linux/drivers/media/video/usbvision/usbvision-video.c b/linux/drivers/media/video/usbvision/usbvision-video.c index b76295a5b..782ee6436 100644 --- a/linux/drivers/media/video/usbvision/usbvision-video.c +++ b/linux/drivers/media/video/usbvision/usbvision-video.c @@ -360,9 +360,7 @@ static void usbvision_remove_sysfs(struct video_device *vdev) */ static int usbvision_v4l2_open(struct inode *inode, struct file *file) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int errCode = 0; PDEBUG(DBG_IO, "open"); @@ -439,9 +437,7 @@ static int usbvision_v4l2_open(struct inode *inode, struct file *file) */ static int usbvision_v4l2_close(struct inode *inode, struct file *file) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); PDEBUG(DBG_IO, "close"); mutex_lock(&usbvision->lock); @@ -486,9 +482,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file) static int vidioc_g_register (struct file *file, void *priv, struct v4l2_register *reg) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int errCode; if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) @@ -507,9 +501,7 @@ static int vidioc_g_register (struct file *file, void *priv, static int vidioc_s_register (struct file *file, void *priv, struct v4l2_register *reg) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int errCode; if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) @@ -528,9 +520,7 @@ static int vidioc_s_register (struct file *file, void *priv, static int vidioc_querycap (struct file *file, void *priv, struct v4l2_capability *vc) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); strlcpy(vc->card, @@ -550,9 +540,7 @@ static int vidioc_querycap (struct file *file, void *priv, static int vidioc_enum_input (struct file *file, void *priv, struct v4l2_input *vi) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int chan; if ((vi->index >= usbvision->video_inputs) || (vi->index < 0) ) @@ -605,9 +593,7 @@ static int vidioc_enum_input (struct file *file, void *priv, static int vidioc_g_input (struct file *file, void *priv, unsigned int *input) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); *input = usbvision->ctl_input; return 0; @@ -615,9 +601,7 @@ static int vidioc_g_input (struct file *file, void *priv, unsigned int *input) static int vidioc_s_input (struct file *file, void *priv, unsigned int input) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); if ((input >= usbvision->video_inputs) || (input < 0) ) return -EINVAL; @@ -634,9 +618,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int input) static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); + usbvision->tvnormId=*id; mutex_lock(&usbvision->lock); @@ -652,9 +635,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) static int vidioc_g_tuner (struct file *file, void *priv, struct v4l2_tuner *vt) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); if (!usbvision->have_tuner || vt->index) // Only tuner 0 return -EINVAL; @@ -673,9 +654,7 @@ static int vidioc_g_tuner (struct file *file, void *priv, static int vidioc_s_tuner (struct file *file, void *priv, struct v4l2_tuner *vt) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); // Only no or one tuner for now if (!usbvision->have_tuner || vt->index) @@ -689,9 +668,7 @@ static int vidioc_s_tuner (struct file *file, void *priv, static int vidioc_g_frequency (struct file *file, void *priv, struct v4l2_frequency *freq) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); freq->tuner = 0; // Only one tuner if(usbvision->radio) { @@ -707,9 +684,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, static int vidioc_s_frequency (struct file *file, void *priv, struct v4l2_frequency *freq) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); // Only no or one tuner for now if (!usbvision->have_tuner || freq->tuner) @@ -723,9 +698,7 @@ static int vidioc_s_frequency (struct file *file, void *priv, static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); memset(a,0,sizeof(*a)); if(usbvision->radio) { @@ -750,9 +723,7 @@ static int vidioc_s_audio (struct file *file, void *fh, static int vidioc_queryctrl (struct file *file, void *priv, struct v4l2_queryctrl *ctrl) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int id=ctrl->id; memset(ctrl,0,sizeof(*ctrl)); @@ -769,9 +740,7 @@ static int vidioc_queryctrl (struct file *file, void *priv, static int vidioc_g_ctrl (struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); call_i2c_clients(usbvision, VIDIOC_G_CTRL, ctrl); return 0; @@ -780,9 +749,7 @@ static int vidioc_g_ctrl (struct file *file, void *priv, static int vidioc_s_ctrl (struct file *file, void *priv, struct v4l2_control *ctrl) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); call_i2c_clients(usbvision, VIDIOC_S_CTRL, ctrl); return 0; @@ -791,9 +758,7 @@ static int vidioc_s_ctrl (struct file *file, void *priv, static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *vr) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int ret; RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES); @@ -821,9 +786,7 @@ static int vidioc_reqbufs (struct file *file, static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *vb) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); struct usbvision_frame *frame; /* FIXME : must control @@ -859,9 +822,7 @@ static int vidioc_querybuf (struct file *file, static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); struct usbvision_frame *frame; unsigned long lock_flags; @@ -898,9 +859,7 @@ static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb) static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int ret; struct usbvision_frame *f; unsigned long lock_flags; @@ -941,9 +900,7 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb) static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; usbvision->streaming = Stream_On; @@ -955,9 +912,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type type) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int b=V4L2_BUF_TYPE_VIDEO_CAPTURE; if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -990,9 +945,7 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, struct v4l2_format *vf) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); vf->fmt.pix.width = usbvision->curwidth; vf->fmt.pix.height = usbvision->curheight; vf->fmt.pix.pixelformat = usbvision->palette.format; @@ -1008,9 +961,7 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, struct v4l2_format *vf) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int formatIdx; /* Find requested format in available ones */ @@ -1038,9 +989,7 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int ret; if( 0 != (ret=vidioc_try_fmt_vid_cap (file, priv, vf)) ) { @@ -1068,9 +1017,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int noblock = file->f_flags & O_NONBLOCK; unsigned long lock_flags; @@ -1179,10 +1126,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) start = vma->vm_start; void *pos; u32 i; - - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); PDEBUG(DBG_MMAP, "mmap"); @@ -1239,9 +1183,7 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma) */ static int usbvision_radio_open(struct inode *inode, struct file *file) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int errCode = 0; PDEBUG(DBG_IO, "%s:", __func__); @@ -1291,9 +1233,7 @@ out: static int usbvision_radio_close(struct inode *inode, struct file *file) { - struct video_device *dev = video_devdata(file); - struct usb_usbvision *usbvision = - (struct usb_usbvision *) video_get_drvdata(dev); + struct usb_usbvision *usbvision = video_drvdata(file); int errCode = 0; PDEBUG(DBG_IO, ""); diff --git a/linux/drivers/media/video/uvc/uvc_driver.c b/linux/drivers/media/video/uvc/uvc_driver.c index 7e102034d..b2482502a 100644 --- a/linux/drivers/media/video/uvc/uvc_driver.c +++ b/linux/drivers/media/video/uvc/uvc_driver.c @@ -1663,7 +1663,7 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message) return uvc_video_suspend(&dev->video); } -static int uvc_resume(struct usb_interface *intf) +static int __uvc_resume(struct usb_interface *intf, int reset) { struct uvc_device *dev = usb_get_intfdata(intf); int ret; @@ -1672,7 +1672,7 @@ static int uvc_resume(struct usb_interface *intf) intf->cur_altsetting->desc.bInterfaceNumber); if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) { - if ((ret = uvc_ctrl_resume_device(dev)) < 0) + if (reset && (ret = uvc_ctrl_resume_device(dev)) < 0) return ret; return uvc_status_resume(dev); @@ -1687,6 +1687,18 @@ static int uvc_resume(struct usb_interface *intf) return uvc_video_resume(&dev->video); } +static int uvc_resume(struct usb_interface *intf) +{ + return __uvc_resume(intf, 0); +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) +static int uvc_reset_resume(struct usb_interface *intf) +{ + return __uvc_resume(intf, 1); +} +#endif + /* ------------------------------------------------------------------------ * Driver initialization and cleanup */ @@ -1920,6 +1932,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_PROBE_MINMAX }, + /* Fujitsu Amilo SI2636 - Bison Electronics */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x5986, + .idProduct = 0x0202, + .bInterfaceClass = USB_CLASS_VIDEO, + .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, @@ -1952,6 +1973,9 @@ struct uvc_driver uvc_driver = { .disconnect = uvc_disconnect, .suspend = uvc_suspend, .resume = uvc_resume, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23) + .reset_resume = uvc_reset_resume, +#endif .id_table = uvc_ids, .supports_autosuspend = 1, }, diff --git a/linux/drivers/media/video/uvc/uvc_v4l2.c b/linux/drivers/media/video/uvc/uvc_v4l2.c index d7bd71be4..d4758c8e1 100644 --- a/linux/drivers/media/video/uvc/uvc_v4l2.c +++ b/linux/drivers/media/video/uvc/uvc_v4l2.c @@ -400,15 +400,13 @@ static int uvc_has_privileges(struct uvc_fh *handle) static int uvc_v4l2_open(struct inode *inode, struct file *file) { - struct video_device *vdev; struct uvc_video_device *video; struct uvc_fh *handle; int ret = 0; uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n"); mutex_lock(&uvc_driver.open_mutex); - vdev = video_devdata(file); - video = video_get_drvdata(vdev); + video = video_drvdata(file); if (video->dev->state & UVC_DEV_DISCONNECTED) { ret = -ENODEV; @@ -440,8 +438,7 @@ done: static int uvc_v4l2_release(struct inode *inode, struct file *file) { - struct video_device *vdev = video_devdata(file); - struct uvc_video_device *video = video_get_drvdata(vdev); + struct uvc_video_device *video = video_drvdata(file); struct uvc_fh *handle = (struct uvc_fh *)file->private_data; uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n"); @@ -1031,8 +1028,7 @@ static struct vm_operations_struct uvc_vm_ops = { static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma) { - struct video_device *vdev = video_devdata(file); - struct uvc_video_device *video = video_get_drvdata(vdev); + struct uvc_video_device *video = video_drvdata(file); struct uvc_buffer *uninitialized_var(buffer); struct page *page; unsigned long addr, start, size; @@ -1085,8 +1081,7 @@ done: static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait) { - struct video_device *vdev = video_devdata(file); - struct uvc_video_device *video = video_get_drvdata(vdev); + struct uvc_video_device *video = video_drvdata(file); uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n"); diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index 03dc3a519..593aebffe 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -455,7 +455,8 @@ static void uvc_video_decode_isoc(struct urb *urb, urb->iso_frame_desc[i].actual_length - ret); /* Process the header again. */ - uvc_video_decode_end(video, buf, mem, ret); + uvc_video_decode_end(video, buf, mem, + urb->iso_frame_desc[i].actual_length); if (buf->state == UVC_BUF_STATE_DONE || buf->state == UVC_BUF_STATE_ERROR) @@ -512,7 +513,7 @@ static void uvc_video_decode_bulk(struct urb *urb, video->bulk.payload_size >= video->bulk.max_payload_size) { if (!video->bulk.skip_payload && buf != NULL) { uvc_video_decode_end(video, buf, video->bulk.header, - video->bulk.header_size); + video->bulk.payload_size); if (buf->state == UVC_BUF_STATE_DONE || buf->state == UVC_BUF_STATE_ERROR) buf = uvc_queue_next_buffer(&video->queue, buf); diff --git a/linux/drivers/media/video/v4l2-dev.c b/linux/drivers/media/video/v4l2-dev.c index 594f2477f..a2daea31c 100644 --- a/linux/drivers/media/video/v4l2-dev.c +++ b/linux/drivers/media/video/v4l2-dev.c @@ -44,6 +44,7 @@ static ssize_t show_index(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, dev); + return sprintf(buf, "%i\n", vfd->index); } @@ -51,6 +52,7 @@ static ssize_t show_name(struct device *cd, struct device_attribute *attr, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, dev); + return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); } @@ -63,12 +65,14 @@ static struct device_attribute video_device_attrs[] = { static ssize_t show_index(struct class_device *cd, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, dev); + return sprintf(buf, "%i\n", vfd->index); } static ssize_t show_name(struct class_device *cd, char *buf) { struct video_device *vfd = container_of(cd, struct video_device, dev); + return sprintf(buf, "%.*s\n", (int)sizeof(vfd->name), vfd->name); } @@ -76,12 +80,15 @@ static CLASS_DEVICE_ATTR(index, S_IRUGO, show_index, NULL); static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL); #endif +/* + * Active devices + */ +static struct video_device *video_device[VIDEO_NUM_DEVICES]; +static DEFINE_MUTEX(videodev_lock); + struct video_device *video_device_alloc(void) { - struct video_device *vfd; - - vfd = kzalloc(sizeof(*vfd), GFP_KERNEL); - return vfd; + return kzalloc(sizeof(struct video_device), GFP_KERNEL); } EXPORT_SYMBOL(video_device_alloc); @@ -91,6 +98,42 @@ void video_device_release(struct video_device *vfd) } EXPORT_SYMBOL(video_device_release); +void video_device_release_empty(struct video_device *vfd) +{ + /* Do nothing */ + /* Only valid when the video_device struct is a static. */ +} +EXPORT_SYMBOL(video_device_release_empty); + +/* Called when the last user of the character device is gone. */ +static void v4l2_chardev_release(struct kobject *kobj) +{ + struct video_device *vfd = container_of(kobj, struct video_device, cdev.kobj); + + mutex_lock(&videodev_lock); + if (video_device[vfd->minor] != vfd) { + mutex_unlock(&videodev_lock); + BUG(); + return; + } + + /* Free up this device for reuse */ + video_device[vfd->minor] = NULL; + mutex_unlock(&videodev_lock); + + /* Release the character device */ + vfd->cdev_release(kobj); + /* Release video_device and perform other + cleanups as needed. */ + if (vfd->release) + vfd->release(vfd); +} + +/* The new kobj_type for the character device */ +static struct kobj_type v4l2_ktype_cdev_default = { + .release = v4l2_chardev_release, +}; + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) static void video_release(struct class_device *cd) #else @@ -99,12 +142,11 @@ static void video_release(struct device *cd) { struct video_device *vfd = container_of(cd, struct video_device, dev); -#if 1 /* keep */ - /* needed until all drivers are fixed */ - if (!vfd->release) - return; -#endif - vfd->release(vfd); + /* It's now safe to delete the char device. + This will either trigger the v4l2_chardev_release immediately (if + the refcount goes to 0) or later when the last user of the + character device closes it. */ + cdev_del(&vfd->cdev); } static struct class video_class = { @@ -117,13 +159,6 @@ static struct class video_class = { #endif }; -/* - * Active devices - */ - -static struct video_device *video_device[VIDEO_NUM_DEVICES]; -static DEFINE_MUTEX(videodev_lock); - struct video_device *video_devdata(struct file *file) { #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20) @@ -134,79 +169,6 @@ struct video_device *video_devdata(struct file *file) } EXPORT_SYMBOL(video_devdata); -/* - * Open a video device - FIXME: Obsoleted - */ -static int video_open(struct inode *inode, struct file *file) -{ - unsigned int minor = iminor(inode); - int err = 0; - struct video_device *vfl; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) - const struct file_operations *old_fops; -#else - struct file_operations *old_fops; -#endif - - if (minor >= VIDEO_NUM_DEVICES) - return -ENODEV; - mutex_lock(&videodev_lock); - vfl = video_device[minor]; - if (vfl == NULL) { - mutex_unlock(&videodev_lock); - request_module("char-major-%d-%d", VIDEO_MAJOR, minor); - mutex_lock(&videodev_lock); - vfl = video_device[minor]; - if (vfl == NULL) { - mutex_unlock(&videodev_lock); - return -ENODEV; - } - } - old_fops = file->f_op; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) - file->f_op = fops_get(vfl->fops); -#else - file->f_op = (struct file_operations *)fops_get(vfl->fops); -#endif - if (file->f_op->open) - err = file->f_op->open(inode, file); - if (err) { - fops_put(file->f_op); - file->f_op = fops_get(old_fops); - } - fops_put(old_fops); - mutex_unlock(&videodev_lock); - return err; -} - -/* - * open/release helper functions -- handle exclusive opens - * Should be removed soon - */ -int video_exclusive_open(struct inode *inode, struct file *file) -{ - struct video_device *vfl = video_devdata(file); - int retval = 0; - - mutex_lock(&vfl->lock); - if (vfl->users) - retval = -EBUSY; - else - vfl->users++; - mutex_unlock(&vfl->lock); - return retval; -} -EXPORT_SYMBOL(video_exclusive_open); - -int video_exclusive_release(struct inode *inode, struct file *file) -{ - struct video_device *vfl = video_devdata(file); - - vfl->users--; - return 0; -} -EXPORT_SYMBOL(video_exclusive_release); - /** * get_index - assign stream number based on parent device * @vdev: video_device to assign index number to, vdev->dev should be assigned @@ -291,6 +253,13 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, int end; int ret; char *name_base; + void *priv = video_get_drvdata(vfd); + + /* the release callback MUST be present */ + BUG_ON(!vfd->release); + + if (vfd == NULL) + return -EINVAL; switch (type) { case VFL_TYPE_GRABBER: @@ -319,9 +288,16 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, return -EINVAL; } + /* Initialize the character device */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) + cdev_init(&vfd->cdev, vfd->fops); +#else + cdev_init(&vfd->cdev, (struct file_operations *)vfd->fops); +#endif + vfd->cdev.owner = vfd->fops->owner; /* pick a minor number */ mutex_lock(&videodev_lock); - if (nr >= 0 && nr < end-base) { + if (nr >= 0 && nr < end-base) { /* use the one the driver asked for */ i = base + nr; if (NULL != video_device[i]) { @@ -352,10 +328,16 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, goto fail_minor; } - mutex_init(&vfd->lock); - + ret = cdev_add(&vfd->cdev, MKDEV(VIDEO_MAJOR, vfd->minor), 1); + if (ret < 0) { + printk(KERN_ERR "%s: cdev_add failed\n", __func__); + goto fail_minor; + } /* sysfs class */ - memset(&vfd->dev, 0x00, sizeof(vfd->dev)); + memset(&vfd->dev, 0, sizeof(vfd->dev)); + /* The memset above cleared the device's drvdata, so + put back the copy we made earlier. */ + video_set_drvdata(vfd, priv); vfd->dev.class = &video_class; vfd->dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) @@ -371,41 +353,38 @@ int video_register_device_index(struct video_device *vfd, int type, int nr, #endif if (ret < 0) { printk(KERN_ERR "%s: device_register failed\n", __func__); - goto fail_minor; + goto del_cdev; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) - ret = class_device_create_file(&vfd->dev, - &class_device_attr_name); + ret = class_device_create_file(&vfd->dev, &class_device_attr_name); if (ret < 0) { printk(KERN_ERR "%s: class_device_create_file 'name' failed\n", __func__); class_device_unregister(&vfd->dev); - goto fail_minor; + goto del_cdev; } - ret = class_device_create_file(&vfd->dev, - &class_device_attr_index); + ret = class_device_create_file(&vfd->dev, &class_device_attr_index); if (ret < 0) { printk(KERN_ERR "%s: class_device_create_file 'index' failed\n", __func__); class_device_unregister(&vfd->dev); - goto fail_minor; + goto del_cdev; } #endif - -#if 1 /* keep */ - /* needed until all drivers are fixed */ - if (!vfd->release) - printk(KERN_WARNING "videodev: \"%s\" has no release callback. " - "Please fix your driver for proper sysfs support, see " - "http://lwn.net/Articles/36850/\n", vfd->name); -#endif + /* Remember the cdev's release function */ + vfd->cdev_release = vfd->cdev.kobj.ktype->release; + /* Install our own */ + vfd->cdev.kobj.ktype = &v4l2_ktype_cdev_default; return 0; +del_cdev: + cdev_del(&vfd->cdev); + fail_minor: mutex_lock(&videodev_lock); video_device[vfd->minor] = NULL; - vfd->minor = -1; mutex_unlock(&videodev_lock); + vfd->minor = -1; return ret; } EXPORT_SYMBOL(video_register_device_index); @@ -420,51 +399,33 @@ EXPORT_SYMBOL(video_register_device_index); void video_unregister_device(struct video_device *vfd) { - mutex_lock(&videodev_lock); - if (video_device[vfd->minor] != vfd) - panic("videodev: bad unregister"); - - video_device[vfd->minor] = NULL; #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) class_device_unregister(&vfd->dev); #else device_unregister(&vfd->dev); #endif - mutex_unlock(&videodev_lock); } EXPORT_SYMBOL(video_unregister_device); /* - * Video fs operations - */ -static const struct file_operations video_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .open = video_open, -}; - -/* * Initialise video for linux */ - static int __init videodev_init(void) { + dev_t dev = MKDEV(VIDEO_MAJOR, 0); int ret; printk(KERN_INFO "Linux video capture interface: v2.00\n"); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) - if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) { -#else - if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, - (struct file_operations *)&video_fops)) { -#endif - printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR); - return -EIO; + ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME); + if (ret < 0) { + printk(KERN_WARNING "videodev: unable to get major %d\n", + VIDEO_MAJOR); + return ret; } ret = class_register(&video_class); if (ret < 0) { - unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); + unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); printk(KERN_WARNING "video_dev: class_register failed\n"); return -EIO; } @@ -474,8 +435,10 @@ static int __init videodev_init(void) static void __exit videodev_exit(void) { + dev_t dev = MKDEV(VIDEO_MAJOR, 0); + class_unregister(&video_class); - unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); + unregister_chrdev_region(dev, VIDEO_NUM_DEVICES); } module_init(videodev_init) diff --git a/linux/drivers/media/video/vino.c b/linux/drivers/media/video/vino.c index 1e61b3e5a..08eb57818 100644 --- a/linux/drivers/media/video/vino.c +++ b/linux/drivers/media/video/vino.c @@ -4028,8 +4028,7 @@ out: static int vino_open(struct inode *inode, struct file *file) { - struct video_device *dev = video_devdata(file); - struct vino_channel_settings *vcs = video_get_drvdata(dev); + struct vino_channel_settings *vcs = video_drvdata(file); int ret = 0; dprintk("open(): channel = %c\n", (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B'); @@ -4060,8 +4059,7 @@ static int vino_open(struct inode *inode, struct file *file) static int vino_close(struct inode *inode, struct file *file) { - struct video_device *dev = video_devdata(file); - struct vino_channel_settings *vcs = video_get_drvdata(dev); + struct vino_channel_settings *vcs = video_drvdata(file); dprintk("close():\n"); mutex_lock(&vcs->mutex); @@ -4104,8 +4102,7 @@ static struct vm_operations_struct vino_vm_ops = { static int vino_mmap(struct file *file, struct vm_area_struct *vma) { - struct video_device *dev = video_devdata(file); - struct vino_channel_settings *vcs = video_get_drvdata(dev); + struct vino_channel_settings *vcs = video_drvdata(file); unsigned long start = vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start; @@ -4210,8 +4207,7 @@ out: static unsigned int vino_poll(struct file *file, poll_table *pt) { - struct video_device *dev = video_devdata(file); - struct vino_channel_settings *vcs = video_get_drvdata(dev); + struct vino_channel_settings *vcs = video_drvdata(file); unsigned int outgoing; unsigned int ret = 0; @@ -4251,8 +4247,7 @@ error: static int vino_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { - struct video_device *dev = video_devdata(file); - struct vino_channel_settings *vcs = video_get_drvdata(dev); + struct vino_channel_settings *vcs = video_drvdata(file); #ifdef VINO_DEBUG switch (_IOC_TYPE(cmd)) { @@ -4359,8 +4354,7 @@ static int vino_do_ioctl(struct inode *inode, struct file *file, static int vino_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct video_device *dev = video_devdata(file); - struct vino_channel_settings *vcs = video_get_drvdata(dev); + struct vino_channel_settings *vcs = video_drvdata(file); int ret; if (mutex_lock_interruptible(&vcs->mutex)) diff --git a/linux/drivers/media/video/vivi.c b/linux/drivers/media/video/vivi.c index 2f18381b6..f6a12b184 100644 --- a/linux/drivers/media/video/vivi.c +++ b/linux/drivers/media/video/vivi.c @@ -1029,13 +1029,13 @@ static int vivi_release(void) dev = list_entry(list, struct vivi_dev, vivi_devlist); if (-1 != dev->vfd->minor) { - video_unregister_device(dev->vfd); - printk(KERN_INFO "%s: /dev/video%d unregistered.\n", + printk(KERN_INFO "%s: unregistering /dev/video%d\n", VIVI_MODULE_NAME, dev->vfd->minor); + video_unregister_device(dev->vfd); } else { - video_device_release(dev->vfd); - printk(KERN_INFO "%s: /dev/video%d released.\n", + printk(KERN_INFO "%s: releasing /dev/video%d\n", VIVI_MODULE_NAME, dev->vfd->minor); + video_device_release(dev->vfd); } kfree(dev); @@ -1112,19 +1112,29 @@ static struct video_device vivi_template = { Initialization and module stuff ------------------------------------------------------------------*/ +/* This routine allocates from 1 to n_devs virtual drivers. + + The real maximum number of virtual drivers will depend on how many drivers + will succeed. This is limited to the maximum number of devices that + videodev supports. Since there are 64 minors for video grabbers, this is + currently the theoretical maximum limit. However, a further limit does + exist at videodev that forbids any driver to register more than 32 video + grabbers. + */ static int __init vivi_init(void) { int ret = -ENOMEM, i; struct vivi_dev *dev; struct video_device *vfd; + if (n_devs <= 0) + n_devs = 1; + for (i = 0; i < n_devs; i++) { dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (NULL == dev) + if (!dev) break; - list_add_tail(&dev->vivi_devlist, &vivi_devlist); - /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); init_waitqueue_head(&dev->vidq.wq); @@ -1134,14 +1144,27 @@ static int __init vivi_init(void) mutex_init(&dev->mutex); vfd = video_device_alloc(); - if (NULL == vfd) + if (!vfd) { + kfree(dev); break; + } *vfd = vivi_template; ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); - if (ret < 0) + if (ret < 0) { + video_device_release(vfd); + kfree(dev); + + /* If some registers succeeded, keep driver */ + if (i) + ret = 0; + break; + } + + /* Now that everything is fine, let's add it to device list */ + list_add_tail(&dev->vivi_devlist, &vivi_devlist); snprintf(vfd->name, sizeof(vfd->name), "%s (%i)", vivi_template.name, vfd->minor); @@ -1157,11 +1180,16 @@ static int __init vivi_init(void) if (ret < 0) { vivi_release(); printk(KERN_INFO "Error %d while loading vivi driver\n", ret); - } else + } else { printk(KERN_INFO "Video Technology Magazine Virtual Video " "Capture Board ver %u.%u.%u successfully loaded.\n", (VIVI_VERSION >> 16) & 0xFF, (VIVI_VERSION >> 8) & 0xFF, VIVI_VERSION & 0xFF); + + /* n_devs will reflect the actual number of allocated devices */ + n_devs = i; + } + return ret; } @@ -1177,10 +1205,10 @@ MODULE_DESCRIPTION("Video Technology Magazine Virtual Video Capture Board"); MODULE_AUTHOR("Mauro Carvalho Chehab, Ted Walther and John Sokol"); MODULE_LICENSE("Dual BSD/GPL"); -module_param(video_nr, int, 0); +module_param(video_nr, uint, 0444); MODULE_PARM_DESC(video_nr, "video iminor start number"); -module_param(n_devs, int, 0); +module_param(n_devs, uint, 0444); MODULE_PARM_DESC(n_devs, "number of video devices to create"); module_param_named(debug, vivi_template.debug, int, 0444); diff --git a/linux/drivers/media/video/vpx3220.c b/linux/drivers/media/video/vpx3220.c index 989166eec..896af1a12 100644 --- a/linux/drivers/media/video/vpx3220.c +++ b/linux/drivers/media/video/vpx3220.c @@ -24,8 +24,6 @@ #include <linux/types.h> #include <linux/slab.h> -#include <linux/byteorder/swab.h> - #include <asm/io.h> #include <asm/uaccess.h> diff --git a/linux/drivers/media/video/w9966.c b/linux/drivers/media/video/w9966.c index 6aefc6566..f3f28c232 100644 --- a/linux/drivers/media/video/w9966.c +++ b/linux/drivers/media/video/w9966.c @@ -114,6 +114,7 @@ struct w9966_dev { signed char contrast; signed char color; signed char hue; + unsigned long in_use; }; /* @@ -185,10 +186,25 @@ static int w9966_v4l_ioctl(struct inode *inode, struct file *file, static ssize_t w9966_v4l_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); +static int w9966_exclusive_open(struct inode *inode, struct file *file) +{ + struct w9966_dev *cam = video_drvdata(file); + + return test_and_set_bit(0, &cam->in_use) ? -EBUSY : 0; +} + +static int w9966_exclusive_release(struct inode *inode, struct file *file) +{ + struct w9966_dev *cam = video_drvdata(file); + + clear_bit(0, &cam->in_use); + return 0; +} + static const struct file_operations w9966_fops = { .owner = THIS_MODULE, - .open = video_exclusive_open, - .release = video_exclusive_release, + .open = w9966_exclusive_open, + .release = w9966_exclusive_release, .ioctl = w9966_v4l_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = v4l_compat_ioctl32, @@ -199,6 +215,7 @@ static const struct file_operations w9966_fops = { static struct video_device w9966_template = { .name = W9966_DRIVERNAME, .fops = &w9966_fops, + .release = video_device_release_empty, }; /* @@ -333,9 +350,9 @@ static int w9966_init(struct w9966_dev* cam, struct parport* port) // Fill in the video_device struct and register us to v4l memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device)); - cam->vdev.priv = cam; + video_set_drvdata(&cam->vdev, cam); - if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1) + if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) return -1; w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); @@ -714,8 +731,7 @@ static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data) static int w9966_v4l_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg) { - struct video_device *vdev = video_devdata(file); - struct w9966_dev *cam = vdev->priv; + struct w9966_dev *cam = video_drvdata(file); switch(cmd) { @@ -873,8 +889,7 @@ static int w9966_v4l_ioctl(struct inode *inode, struct file *file, static ssize_t w9966_v4l_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct video_device *vdev = video_devdata(file); - struct w9966_dev *cam = vdev->priv; + struct w9966_dev *cam = video_drvdata(file); unsigned char addr = 0xa0; // ECP, read, CCD-transfer, 00000 unsigned char __user *dest = (unsigned char __user *)buf; unsigned long dleft = count; diff --git a/linux/drivers/media/video/w9968cf.c b/linux/drivers/media/video/w9968cf.c index 666438e8d..4e7a8400b 100644 --- a/linux/drivers/media/video/w9968cf.c +++ b/linux/drivers/media/video/w9968cf.c @@ -919,7 +919,6 @@ static int w9968cf_start_transfer(struct w9968cf_device* cam) for (i = 0; i < W9968CF_URBS; i++) { urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL); - cam->urb[i] = urb; if (!urb) { for (j = 0; j < i; j++) usb_free_urb(cam->urb[j]); @@ -927,6 +926,7 @@ static int w9968cf_start_transfer(struct w9968cf_device* cam) return -ENOMEM; } + cam->urb[i] = urb; urb->dev = udev; urb->context = (void*)cam; urb->pipe = usb_rcvisocpipe(udev, 1); diff --git a/linux/drivers/media/video/wm8739.c b/linux/drivers/media/video/wm8739.c index 3ad19cf13..f9d13b89a 100644 --- a/linux/drivers/media/video/wm8739.c +++ b/linux/drivers/media/video/wm8739.c @@ -280,10 +280,8 @@ static int wm8739_probe(struct i2c_client *client, client->addr << 1, client->adapter->name); state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL); - if (state == NULL) { - kfree(client); + if (state == NULL) return -ENOMEM; - } state->vol_l = 0x17; /* 0dB */ state->vol_r = 0x17; /* 0dB */ state->muted = 0; diff --git a/linux/drivers/media/video/zc0301/zc0301_core.c b/linux/drivers/media/video/zc0301/zc0301_core.c index e59145f65..0be0f095e 100644 --- a/linux/drivers/media/video/zc0301/zc0301_core.c +++ b/linux/drivers/media/video/zc0301/zc0301_core.c @@ -661,7 +661,7 @@ static int zc0301_open(struct inode* inode, struct file* filp) if (!down_read_trylock(&zc0301_dev_lock)) return -EAGAIN; - cam = video_get_drvdata(video_devdata(filp)); + cam = video_drvdata(filp); if (wait_for_completion_interruptible(&cam->probe)) { up_read(&zc0301_dev_lock); @@ -743,7 +743,7 @@ static int zc0301_release(struct inode* inode, struct file* filp) down_write(&zc0301_dev_lock); - cam = video_get_drvdata(video_devdata(filp)); + cam = video_drvdata(filp); zc0301_stop_transfer(cam); zc0301_release_buffers(cam); @@ -763,7 +763,7 @@ static int zc0301_release(struct inode* inode, struct file* filp) static ssize_t zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) { - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + struct zc0301_device *cam = video_drvdata(filp); struct zc0301_frame_t* f, * i; unsigned long lock_flags; long timeout; @@ -870,7 +870,7 @@ exit: static unsigned int zc0301_poll(struct file *filp, poll_table *wait) { - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + struct zc0301_device *cam = video_drvdata(filp); struct zc0301_frame_t* f; unsigned long lock_flags; unsigned int mask = 0; @@ -945,7 +945,7 @@ static struct vm_operations_struct zc0301_vm_ops = { static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma) { - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + struct zc0301_device *cam = video_drvdata(filp); unsigned long size = vma->vm_end - vma->vm_start, start = vma->vm_start; void *pos; @@ -1800,7 +1800,7 @@ zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg) static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp, unsigned int cmd, void __user * arg) { - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + struct zc0301_device *cam = video_drvdata(filp); switch (cmd) { @@ -1895,7 +1895,7 @@ static int zc0301_ioctl_v4l2(struct inode* inode, struct file* filp, static int zc0301_ioctl(struct inode* inode, struct file* filp, unsigned int cmd, unsigned long arg) { - struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); + struct zc0301_device *cam = video_drvdata(filp); int err = 0; if (mutex_lock_interruptible(&cam->fileop_mutex)) @@ -1992,6 +1992,7 @@ zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) cam->v4ldev->fops = &zc0301_fops; cam->v4ldev->minor = video_nr[dev_nr]; cam->v4ldev->release = video_device_release; + cam->v4ldev->parent = &udev->dev; video_set_drvdata(cam->v4ldev, cam); init_completion(&cam->probe); diff --git a/linux/drivers/media/video/zc0301/zc0301_sensor.h b/linux/drivers/media/video/zc0301/zc0301_sensor.h index 8e8276f27..4dc95b5c2 100644 --- a/linux/drivers/media/video/zc0301/zc0301_sensor.h +++ b/linux/drivers/media/video/zc0301/zc0301_sensor.h @@ -61,27 +61,8 @@ zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor); #define ZC0301_ID_TABLE \ static const struct usb_device_id zc0301_id_table[] = { \ - { ZC0301_USB_DEVICE(0x041e, 0x4017, 0xff), }, /* ICM105 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x401c, 0xff), }, /* PAS106 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x401e, 0xff), }, /* HV7131 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x401f, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x4022, 0xff), }, \ - { ZC0301_USB_DEVICE(0x041e, 0x4034, 0xff), }, /* PAS106 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x4035, 0xff), }, /* PAS106 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x4036, 0xff), }, /* HV7131 */ \ - { ZC0301_USB_DEVICE(0x041e, 0x403a, 0xff), }, /* HV7131 */ \ - { ZC0301_USB_DEVICE(0x0458, 0x7007, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x0458, 0x700c, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x0458, 0x700f, 0xff), }, /* TAS5130 */ \ { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \ - { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), }, \ - { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */ \ { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \ - { ZC0301_USB_DEVICE(0x10fd, 0x0128, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130 */ \ - { ZC0301_USB_DEVICE(0x10fd, 0x804e, 0xff), }, /* TAS5130 */ \ { } \ }; diff --git a/linux/drivers/media/video/zoran_device.c b/linux/drivers/media/video/zoran_device.c index e57da2d6f..87f894fa2 100644 --- a/linux/drivers/media/video/zoran_device.c +++ b/linux/drivers/media/video/zoran_device.c @@ -59,8 +59,6 @@ ZR36057_ISR_GIRQ1 | \ ZR36057_ISR_JPEGRepIRQ ) -extern const struct zoran_format zoran_formats[]; - static int lml33dpath; /* default = 0 * 1 will use digital path in capture * mode instead of analog. It can be diff --git a/linux/drivers/media/video/zoran_device.h b/linux/drivers/media/video/zoran_device.h index c46d1b076..d4e0b9b5a 100644 --- a/linux/drivers/media/video/zoran_device.h +++ b/linux/drivers/media/video/zoran_device.h @@ -84,6 +84,14 @@ extern void zoran_set_pci_master(struct zoran *zr, extern void zoran_init_hardware(struct zoran *zr); extern void zr36057_restart(struct zoran *zr); +extern const struct zoran_format zoran_formats[]; + +extern int v4l_nbufs; +extern int v4l_bufsize; +extern int jpg_nbufs; +extern int jpg_bufsize; +extern int pass_through; + /* i2c */ extern int decoder_command(struct zoran *zr, int cmd, diff --git a/linux/drivers/media/video/zoran_driver.c b/linux/drivers/media/video/zoran_driver.c index 78e8430f4..640fa7069 100644 --- a/linux/drivers/media/video/zoran_driver.c +++ b/linux/drivers/media/video/zoran_driver.c @@ -202,12 +202,6 @@ const struct zoran_format zoran_formats[] = { # include <linux/bigphysarea.h> #endif -extern int v4l_nbufs; -extern int v4l_bufsize; -extern int jpg_nbufs; -extern int jpg_bufsize; -extern int pass_through; - static int lock_norm; /* 0 = default 1 = Don't change TV standard (norm) */ module_param(lock_norm, int, 0644); MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)"); diff --git a/linux/drivers/media/video/zoran_procfs.c b/linux/drivers/media/video/zoran_procfs.c index d7bc097da..961950a21 100644 --- a/linux/drivers/media/video/zoran_procfs.c +++ b/linux/drivers/media/video/zoran_procfs.c @@ -162,10 +162,11 @@ static ssize_t zoran_write(struct file *file, const char __user *buffer, return -EFAULT; } string[count] = 0; - dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n", #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) + dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n", ZR_DEVNAME(zr), file->f_dentry->d_name.name, count, zr); #else + dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n", ZR_DEVNAME(zr), file->f_path.dentry->d_name.name, count, zr); #endif ldelim = " \t\n"; diff --git a/linux/firmware/ihex2fw.c b/linux/firmware/ihex2fw.c index 660b191ed..8f7fdaa9e 100644 --- a/linux/firmware/ihex2fw.c +++ b/linux/firmware/ihex2fw.c @@ -250,19 +250,19 @@ static void file_record(struct ihex_binrec *record) static int output_records(int outfd) { - unsigned char zeroes[5] = {0, 0, 0, 0, 0}; + unsigned char zeroes[6] = {0, 0, 0, 0, 0, 0}; struct ihex_binrec *p = records; while (p) { uint16_t writelen = (p->len + 9) & ~3; p->addr = htonl(p->addr); - p->len = htonl(p->len); + p->len = htons(p->len); write(outfd, &p->addr, writelen); p = p->next; } /* EOF record is zero length, since we don't bother to represent the type field in the binary version */ - write(outfd, zeroes, 5); + write(outfd, zeroes, 6); return 0; } diff --git a/linux/include/linux/i2c-id.h b/linux/include/linux/i2c-id.h index bc35aec9d..493435bcd 100644 --- a/linux/include/linux/i2c-id.h +++ b/linux/include/linux/i2c-id.h @@ -39,7 +39,6 @@ #define I2C_DRIVERID_SAA7111A 8 /* video input processor */ #define I2C_DRIVERID_SAA7185B 13 /* video encoder */ #define I2C_DRIVERID_SAA7110 22 /* video decoder */ -#define I2C_DRIVERID_MGATVO 23 /* Matrox TVOut */ #define I2C_DRIVERID_SAA5249 24 /* SAA5249 and compatibles */ #define I2C_DRIVERID_PCF8583 25 /* real time clock */ #define I2C_DRIVERID_TDA7432 27 /* Stereo sound processor */ @@ -94,7 +93,6 @@ #define I2C_HW_B_BT848 0x010005 /* BT848 video boards */ #define I2C_HW_B_VIA 0x010007 /* Via vt82c586b */ #define I2C_HW_B_HYDRA 0x010008 /* Apple Hydra Mac I/O */ -#define I2C_HW_B_G400 0x010009 /* Matrox G400 */ #define I2C_HW_B_I810 0x01000a /* Intel I810 */ #define I2C_HW_B_VOO 0x01000b /* 3dfx Voodoo 3 / Banshee */ #define I2C_HW_B_SCX200 0x01000e /* Nat'l Semi SCx200 I2C */ diff --git a/linux/include/linux/videodev2.h b/linux/include/linux/videodev2.h index 4fd194ce3..63b2787e6 100644 --- a/linux/include/linux/videodev2.h +++ b/linux/include/linux/videodev2.h @@ -261,11 +261,6 @@ struct v4l2_capability { #define V4L2_CAP_ASYNCIO 0x02000000 /* async I/O */ #define V4L2_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */ -/* This flags gets set if the "sensor" is known to be upside down and this can - *not* be fixed using v4l2 flipx/y controls. Note that absence of this flag - is not a guarantee for the image not being upside down. */ -#define V4L2_CAP_SENSOR_UPSIDE_DOWN 0x10000000 - /* * V I D E O I M A G E F O R M A T */ @@ -340,6 +335,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SPCA561 v4l2_fourcc('S', '5', '6', '1') /* compressed GBRG bayer */ #define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P', '2', '0', '7') /* compressed BGGR bayer */ #define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') /* Pixart 73xx JPEG */ +#define V4L2_PIX_FMT_YVYU v4l2_fourcc('Y', 'V', 'Y', 'U') /* 16 YVU 4:2:2 */ /* * F O R M A T E N U M E R A T I O N diff --git a/linux/include/media/v4l2-dev.h b/linux/include/media/v4l2-dev.h index 4e1511b0b..9158ad8b5 100644 --- a/linux/include/media/v4l2-dev.h +++ b/linux/include/media/v4l2-dev.h @@ -9,16 +9,15 @@ #ifndef _V4L2_DEV_H #define _V4L2_DEV_H -#define OBSOLETE_DEVDATA 1 /* to be removed soon */ - #include <linux/poll.h> #include <linux/fs.h> #include <linux/device.h> +#include <linux/cdev.h> #include <linux/mutex.h> -#include <linux/compiler.h> /* need __user */ #include <linux/videodev2.h> #define VIDEO_MAJOR 81 + /* Minor device allocation */ #define MINOR_VFL_TYPE_GRABBER_MIN 0 #define MINOR_VFL_TYPE_GRABBER_MAX 63 @@ -53,6 +52,8 @@ struct video_device #else struct class_device dev; #endif + struct cdev cdev; /* character device */ + void (*cdev_release)(struct kobject *kobj); struct device *parent; /* device parent */ /* device info */ @@ -73,50 +74,58 @@ struct video_device /* ioctl callbacks */ const struct v4l2_ioctl_ops *ioctl_ops; - -#ifdef OBSOLETE_DEVDATA /* to be removed soon */ - /* dev->driver_data will be used instead some day. - * Use the video_{get|set}_drvdata() helper functions, - * so the switch over will be transparent for you. - * Or use {pci|usb}_{get|set}_drvdata() directly. */ - void *priv; -#endif - - /* for videodev.c internal usage -- please don't touch */ - int users; /* video_exclusive_{open|close} ... */ - struct mutex lock; /* ... helper function uses these */ }; -/* Class-dev to video-device */ +/* dev to video-device */ #define to_video_device(cd) container_of(cd, struct video_device, dev) -/* Version 2 functions */ -extern int video_register_device(struct video_device *vfd, int type, int nr); -int video_register_device_index(struct video_device *vfd, int type, int nr, - int index); -void video_unregister_device(struct video_device *); +/* Register and unregister devices. Note that if video_register_device fails, + the release() callback of the video_device structure is *not* called, so + the caller is responsible for freeing any data. Usually that means that + you call video_device_release() on failure. */ +int __must_check video_register_device(struct video_device *vfd, int type, int nr); +int __must_check video_register_device_index(struct video_device *vfd, + int type, int nr, int index); +void video_unregister_device(struct video_device *vfd); + +/* helper functions to alloc/release struct video_device, the + latter can also be used for video_device->release(). */ +struct video_device * __must_check video_device_alloc(void); -/* helper functions to alloc / release struct video_device, the - later can be used for video_device->release() */ -struct video_device *video_device_alloc(void); +/* this release function frees the vfd pointer */ void video_device_release(struct video_device *vfd); -#ifdef OBSOLETE_DEVDATA /* to be removed soon */ +/* this release function does nothing, use when the video_device is a + static global struct. Note that having a static video_device is + a dubious construction at best. */ +void video_device_release_empty(struct video_device *vfd); + /* helper functions to access driver private data. */ static inline void *video_get_drvdata(struct video_device *dev) { - return dev->priv; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) + return class_get_devdata(&dev->dev); +#else + return dev_get_drvdata(&dev->dev); +#endif } static inline void video_set_drvdata(struct video_device *dev, void *data) { - dev->priv = data; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) + class_set_devdata(&dev->dev, data); +#else + dev_set_drvdata(&dev->dev, data); +#endif } -/* Obsolete stuff - Still needed for radio devices and obsolete drivers */ -extern struct video_device* video_devdata(struct file*); -extern int video_exclusive_open(struct inode *inode, struct file *file); -extern int video_exclusive_release(struct inode *inode, struct file *file); -#endif +struct video_device *video_devdata(struct file *file); + +/* Combine video_get_drvdata and video_devdata as this is + used very often. */ +static inline void *video_drvdata(struct file *file) +{ + return video_get_drvdata(video_devdata(file)); +} #endif /* _V4L2_DEV_H */ diff --git a/linux/include/sound/tea575x-tuner.h b/linux/include/sound/tea575x-tuner.h index c85aeca78..4076c6dfb 100644 --- a/linux/include/sound/tea575x-tuner.h +++ b/linux/include/sound/tea575x-tuner.h @@ -57,6 +57,7 @@ struct snd_tea575x { unsigned int freq_fixup; /* crystal onboard */ unsigned int val; /* hw value */ unsigned long freq; /* frequency */ + unsigned long in_use; /* set if the device is in use */ struct snd_tea575x_ops *ops; void *private_data; }; diff --git a/linux/sound/i2c/other/tea575x-tuner.c b/linux/sound/i2c/other/tea575x-tuner.c index c4bd65c94..2d07c8ea5 100644 --- a/linux/sound/i2c/other/tea575x-tuner.c +++ b/linux/sound/i2c/other/tea575x-tuner.c @@ -92,11 +92,10 @@ static void snd_tea575x_set_freq(struct snd_tea575x *tea) static int snd_tea575x_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long data) { - struct video_device *dev = video_devdata(file); #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17) - tea575x_t *tea = video_get_drvdata(dev); + tea575x_t *tea = video_drvdata(file); #else - struct snd_tea575x *tea = video_get_drvdata(dev); + struct snd_tea575x *tea = video_drvdata(file); #endif void __user *arg = (void __user *)data; @@ -186,6 +185,29 @@ static void snd_tea575x_release(struct video_device *vfd) { } +static int snd_tea575x_exclusive_open(struct inode *inode, struct file *file) +{ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17) + tea575x_t *tea = video_drvdata(file); +#else + struct snd_tea575x *tea = video_drvdata(file); +#endif + + return test_and_set_bit(0, &tea->in_use) ? -EBUSY : 0; +} + +static int snd_tea575x_exclusive_release(struct inode *inode, struct file *file) +{ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17) + tea575x_t *tea = video_drvdata(file); +#else + struct snd_tea575x *tea = video_drvdata(file); +#endif + + clear_bit(0, &tea->in_use); + return 0; +} + /* * initialize all the tea575x chips */ @@ -208,9 +230,10 @@ void snd_tea575x_init(struct snd_tea575x *tea) tea->vd.release = snd_tea575x_release; video_set_drvdata(&tea->vd, tea); tea->vd.fops = &tea->fops; + tea->in_use = 0; tea->fops.owner = tea->card->module; - tea->fops.open = video_exclusive_open; - tea->fops.release = video_exclusive_release; + tea->fops.open = snd_tea575x_exclusive_open; + tea->fops.release = snd_tea575x_exclusive_release; tea->fops.ioctl = snd_tea575x_ioctl; if (video_register_device(&tea->vd, VFL_TYPE_RADIO, tea->dev_nr - 1) < 0) { snd_printk(KERN_ERR "unable to register tea575x tuner\n"); diff --git a/mailimport b/mailimport index bd6d36c2e..8ed624179 100755 --- a/mailimport +++ b/mailimport @@ -165,6 +165,12 @@ proccess_patch () { i="$_" + CHECK="`cat $i| perl -ne 'if (m/^Subject:.*FOLDER INTERNAL DATA/) { print -1; }'`" + + if [ "$CHECK" != "" ]; then + return + fi + echo $i if [ "`diffstat -p1 -l "$i"`" == "" ]; then echo "*** ERROR nothing to commit" diff --git a/v4l/Makefile b/v4l/Makefile index 04e74e8e5..2aa856974 100644 --- a/v4l/Makefile +++ b/v4l/Makefile @@ -117,7 +117,7 @@ EXTRA_CFLAGS += $(if $(wildcard $(srctree)/.mm), -DMM_KERNEL) EXTRA_CFLAGS += -include $(obj)/config-compat.h # Allow kernel version compat tests without adding #include's -EXTRA_CFLAGS += -include linux/version.h +EXTRA_CFLAGS += -include include/linux/version.h ################################################# # Kernel 2.4/2.6 specific rules diff --git a/v4l/compat.h b/v4l/compat.h index 6df2f6f13..6e90c0e63 100644 --- a/v4l/compat.h +++ b/v4l/compat.h @@ -230,6 +230,11 @@ static inline int list_is_singular(const struct list_head *head) { return !list_empty(head) && (head->next == head->prev); } + +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) +#define current_uid() (current->uid) #endif #endif diff --git a/v4l/firmware/Makefile b/v4l/firmware/Makefile index e018ad92a..272b2e668 100644 --- a/v4l/firmware/Makefile +++ b/v4l/firmware/Makefile @@ -7,27 +7,26 @@ TARGETS = ihex2fw vicam/firmware.fw dabusb/firmware.fw dabusb/bitstream.bin ttus default: $(TARGETS) clean: - -rm $(TARGETS) + -rm -f $(TARGETS) distclean: clean - -rmdir $(DIRS) + -for i in $(DIRS); do if [ -d $$i ]; then rmdir $$i; fi; done install: default - -for i in $(DIRS); do mkdir /lib/firmware/$$i; done + -for i in $(DIRS); do if [ ! -d /lib/firmware/$$i ]; then mkdir -p /lib/firmware/$$i; fi; done -for i in $(TARGETS); do cp $$i /lib/firmware/$$i; done - + ###### mkdir: - -mkdir $(DIRS) + -for i in $(DIRS); do if [ ! -d $$i ]; then mkdir -p $$i; fi; done ihex2fw: ../../linux/firmware/ihex2fw.c gcc -Wall -o $@ $< vicam/firmware.fw: ../../linux/firmware/vicam/firmware.H16 mkdir - -mkdir vicam ./ihex2fw -w $< $@ dabusb/firmware.fw: ../../linux/firmware/dabusb/firmware.HEX mkdir diff --git a/v4l/scripts/headers_convert.pl b/v4l/scripts/headers_convert.pl new file mode 100755 index 000000000..800a453e1 --- /dev/null +++ b/v4l/scripts/headers_convert.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +# +# headers_install prepare the listed header files for use in +# user space and copy the files to their destination. +# + +use strict; +use warnings; + +foreach (@ARGV) { + my $file = $_; + my $tmpfile = $file . ".tmp"; + + open(my $infile, '<', "$file") + or die "$file: $!\n"; + open(my $outfile, '>', "$tmpfile") or die "$tmpfile: $!\n"; + while (my $line = <$infile>) { + $line =~ s/([\s(])__user\s/$1/g; + $line =~ s/([\s(])__force\s/$1/g; + $line =~ s/([\s(])__iomem\s/$1/g; + $line =~ s/\s__attribute_const__\s/ /g; + $line =~ s/\s__attribute_const__$//g; + $line =~ s/^#include <linux\/compiler.h>//; + printf $outfile "%s", $line; + } + close $outfile; + close $infile; + system "mv $tmpfile $file"; +} +exit 0; diff --git a/v4l2-apps/Makefile b/v4l2-apps/Makefile index 550473435..2bba8fcd4 100644 --- a/v4l2-apps/Makefile +++ b/v4l2-apps/Makefile @@ -1,11 +1,24 @@ # Makefile for linuxtv.org v4l2-apps -.PHONY: all clean install +.PHONY: all distclean clean install -all clean install: +all:: prepare-includes + +all clean install:: $(MAKE) -C lib $@ $(MAKE) -C util $@ $(MAKE) -C test $@ %: make -C .. $(MAKECMDGOALS) + +clean:: + -$(RM) -rf include + +distclean:: clean + +prepare-includes: + -if [ ! -d include ]; then \ + cp -r ../linux/include include ; \ + ../v4l/scripts/headers_convert.pl `find include -type f` ; \ + fi diff --git a/v4l2-apps/lib/Makefile b/v4l2-apps/lib/Makefile index f123f3380..8443039b4 100644 --- a/v4l2-apps/lib/Makefile +++ b/v4l2-apps/lib/Makefile @@ -1,6 +1,6 @@ # Makefile for linuxtv.org v4l2-apps/lib -CPPFLAGS += -I../../linux/include -I.. +CPPFLAGS += -I../include -I.. includes = v4l2.h diff --git a/v4l2-apps/lib/frequencies.c b/v4l2-apps/lib/frequencies.c index 77a79e61c..64379d2b0 100644 --- a/v4l2-apps/lib/frequencies.c +++ b/v4l2-apps/lib/frequencies.c @@ -21,7 +21,7 @@ #include <stdlib.h> -#include "linux/videodev2.h" +#include <linux/videodev2.h> #include "v4l2.h" /* This source was originally written by Nathan Laredo <laredo@gnu.org>. diff --git a/v4l2-apps/lib/libv4l/ChangeLog b/v4l2-apps/lib/libv4l/ChangeLog index 3d4e40ad2..eefe0028b 100644 --- a/v4l2-apps/lib/libv4l/ChangeLog +++ b/v4l2-apps/lib/libv4l/ChangeLog @@ -1,8 +1,20 @@ +libv4l-0.4.2 +------------ +* The bayer pixel order in gspca's sonixb driver was different from that in + the sn9c102 driver from the mainline kernel, a recent gspca patch fixes + this, adjust libv4l to match (and make it work properly with the sn9c102 + driver). + libv4l-0.4.1 ------------ * When the driver supports read() and we are not converting let the driver handle read() instead of emulating it with mmap mode - +* Fix errors and warnings when compiling with ICC (Gregor Jasny) +* Add support to libv4lconvert for rotating images 90 (for Pixart 7302 cams) + or 180 (Philips SPC200NC / Philips SPC300NC) degrees +* Add support for Pixart custom JPEG format +* Hide non public symbols (Gregor Jasny) +* Fix and enable x86_64 asm jpeg decompress helper functions (Gregor Jasny) libv4l-0.4.0 ------------ diff --git a/v4l2-apps/lib/libv4l/Makefile b/v4l2-apps/lib/libv4l/Makefile index 31254a09e..92928271a 100644 --- a/v4l2-apps/lib/libv4l/Makefile +++ b/v4l2-apps/lib/libv4l/Makefile @@ -1,5 +1,5 @@ LIB_RELEASE=0 -V4L2_LIB_VERSION=$(LIB_RELEASE).4.1 +V4L2_LIB_VERSION=$(LIB_RELEASE).4.2 all clean install: $(MAKE) -C libv4lconvert V4L2_LIB_VERSION=$(V4L2_LIB_VERSION) $@ diff --git a/v4l2-apps/lib/libv4l/include/libv4l1.h b/v4l2-apps/lib/libv4l/include/libv4l1.h index 9036ae869..c878cc198 100644 --- a/v4l2-apps/lib/libv4l/include/libv4l1.h +++ b/v4l2-apps/lib/libv4l/include/libv4l1.h @@ -26,9 +26,15 @@ extern "C" { #include <stdio.h> #include <unistd.h> +#if __GNUC__ >= 4 +#define LIBV4L_PUBLIC __attribute__ ((visibility("default"))) +#else +#define LIBV4L_PUBLIC +#endif + /* Point this to a FILE opened for writing when you want to log error and status messages to a file, when NULL errors will get send to stderr */ -extern FILE *v4l1_log_file; +LIBV4L_PUBLIC extern FILE *v4l1_log_file; /* Just like your regular open/close/etc, except that when opening a v4l2 capture only device, full v4l1 emulation is done including emulating the @@ -51,14 +57,14 @@ extern FILE *v4l1_log_file; capture formats, like hw specific bayer compression methods). */ -int v4l1_open (const char *file, int oflag, ...); -int v4l1_close(int fd); -int v4l1_dup(int fd); -int v4l1_ioctl (int fd, unsigned long int request, ...); -ssize_t v4l1_read (int fd, void* buffer, size_t n); -void *v4l1_mmap(void *start, size_t length, int prot, int flags, int fd, +LIBV4L_PUBLIC int v4l1_open (const char *file, int oflag, ...); +LIBV4L_PUBLIC int v4l1_close(int fd); +LIBV4L_PUBLIC int v4l1_dup(int fd); +LIBV4L_PUBLIC int v4l1_ioctl (int fd, unsigned long int request, ...); +LIBV4L_PUBLIC ssize_t v4l1_read (int fd, void* buffer, size_t n); +LIBV4L_PUBLIC void *v4l1_mmap(void *start, size_t length, int prot, int flags, int fd, __off64_t offset); -int v4l1_munmap(void *_start, size_t length); +LIBV4L_PUBLIC int v4l1_munmap(void *_start, size_t length); #ifdef __cplusplus } diff --git a/v4l2-apps/lib/libv4l/include/libv4l2.h b/v4l2-apps/lib/libv4l/include/libv4l2.h index 63529cf4b..b05b57cb6 100644 --- a/v4l2-apps/lib/libv4l/include/libv4l2.h +++ b/v4l2-apps/lib/libv4l/include/libv4l2.h @@ -26,9 +26,15 @@ extern "C" { #endif /* __cplusplus */ +#if __GNUC__ >= 4 +#define LIBV4L_PUBLIC __attribute__ ((visibility("default"))) +#else +#define LIBV4L_PUBLIC +#endif + /* Point this to a FILE opened for writing when you want to log error and status messages to a file, when NULL errors will get send to stderr */ -extern FILE *v4l2_log_file; +LIBV4L_PUBLIC extern FILE *v4l2_log_file; /* Just like your regular open/close/etc, except that format conversion is done if necessary when capturing. That is if you (try to) set a capture @@ -52,14 +58,14 @@ extern FILE *v4l2_log_file; fail. */ -int v4l2_open (const char *file, int oflag, ...); -int v4l2_close(int fd); -int v4l2_dup(int fd); -int v4l2_ioctl (int fd, unsigned long int request, ...); -ssize_t v4l2_read (int fd, void* buffer, size_t n); -void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, +LIBV4L_PUBLIC int v4l2_open (const char *file, int oflag, ...); +LIBV4L_PUBLIC int v4l2_close(int fd); +LIBV4L_PUBLIC int v4l2_dup(int fd); +LIBV4L_PUBLIC int v4l2_ioctl (int fd, unsigned long int request, ...); +LIBV4L_PUBLIC ssize_t v4l2_read (int fd, void* buffer, size_t n); +LIBV4L_PUBLIC void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, __off64_t offset); -int v4l2_munmap(void *_start, size_t length); +LIBV4L_PUBLIC int v4l2_munmap(void *_start, size_t length); /* Misc utility functions */ @@ -70,12 +76,12 @@ int v4l2_munmap(void *_start, size_t length); Normally returns 0, even if the cid did not exist or was locked, returns non 0 when an other error occured. */ -int v4l2_set_control(int fd, int cid, int value); +LIBV4L_PUBLIC int v4l2_set_control(int fd, int cid, int value); /* This function returns a value of 0 - 65535, scaled to from the actual range of the given v4l control id. when the cid does not exist, could not be accessed for some reason, or some error occured 0 is returned. */ -int v4l2_get_control(int fd, int cid); +LIBV4L_PUBLIC int v4l2_get_control(int fd, int cid); /* "low level" access functions, these functions allow somewhat lower level @@ -95,7 +101,7 @@ int v4l2_get_control(int fd, int cid); Returns fd on success, -1 if the fd is not suitable for use through libv4l2 (note the fd is left open in this case). */ -int v4l2_fd_open(int fd, int v4l2_flags); +LIBV4L_PUBLIC int v4l2_fd_open(int fd, int v4l2_flags); #ifdef __cplusplus } diff --git a/v4l2-apps/lib/libv4l/include/libv4lconvert.h b/v4l2-apps/lib/libv4l/include/libv4lconvert.h index d8446dac8..87e41ceaa 100644 --- a/v4l2-apps/lib/libv4l/include/libv4lconvert.h +++ b/v4l2-apps/lib/libv4l/include/libv4lconvert.h @@ -31,34 +31,45 @@ extern "C" { #endif /* __cplusplus */ +#if __GNUC__ >= 4 +#define LIBV4L_PUBLIC __attribute__ ((visibility("default"))) +#else +#define LIBV4L_PUBLIC +#endif + struct v4lconvert_data; -struct v4lconvert_data *v4lconvert_create(int fd); -void v4lconvert_destroy(struct v4lconvert_data *data); +LIBV4L_PUBLIC struct v4lconvert_data *v4lconvert_create(int fd); +LIBV4L_PUBLIC void v4lconvert_destroy(struct v4lconvert_data *data); /* With regards to dest_fmt just like VIDIOC_TRY_FMT, except that the try format will succeed and return the requested V4L2_PIX_FMT_foo in dest_fmt if the cam has a format from which v4lconvert can convert to dest_fmt. The real format to which the cam should be set is returned through src_fmt when not NULL. */ -int v4lconvert_try_format(struct v4lconvert_data *data, +LIBV4L_PUBLIC int v4lconvert_try_format(struct v4lconvert_data *data, struct v4l2_format *dest_fmt, /* in / out */ struct v4l2_format *src_fmt /* out */ ); /* Just like VIDIOC_ENUM_FMT, except that the emulated formats are added at the end of the list */ -int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt); +LIBV4L_PUBLIC int v4lconvert_enum_fmt(struct v4lconvert_data *data, struct v4l2_fmtdesc *fmt); + +/* Is conversion necessary or can the app use the data directly? */ +LIBV4L_PUBLIC int v4lconvert_needs_conversion(struct v4lconvert_data *data, + const struct v4l2_format *src_fmt, /* in */ + const struct v4l2_format *dest_fmt); /* in */ /* return value of -1 on error, otherwise the amount of bytes written to dest */ -int v4lconvert_convert(struct v4lconvert_data *data, +LIBV4L_PUBLIC int v4lconvert_convert(struct v4lconvert_data *data, const struct v4l2_format *src_fmt, /* in */ const struct v4l2_format *dest_fmt, /* in */ unsigned char *src, int src_size, unsigned char *dest, int dest_size); /* get a string describing the last error*/ -const char *v4lconvert_get_error_message(struct v4lconvert_data *data); +LIBV4L_PUBLIC const char *v4lconvert_get_error_message(struct v4lconvert_data *data); #ifdef __cplusplus } diff --git a/v4l2-apps/lib/libv4l/libv4l1/Makefile b/v4l2-apps/lib/libv4l/libv4l1/Makefile index c92731daa..27848477e 100644 --- a/v4l2-apps/lib/libv4l/libv4l1/Makefile +++ b/v4l2-apps/lib/libv4l/libv4l1/Makefile @@ -1,7 +1,7 @@ -CPPFLAGS = -I../include -I../../../../linux/include +override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden CFLAGS := -g -O1 -CFLAGS += -Wall -W -Wno-unused -Wpointer-arith -Wstrict-prototypes +CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes LIBS = -lpthread @@ -17,7 +17,7 @@ else V4L1_LIB = libv4l1.so V4L1_OBJS += ../libv4l2/libv4l2.so TARGETS += $(V4L1COMPAT) -CPPFLAGS += -fPIC +override CPPFLAGS += -fPIC endif ifeq ($(LIB_RELEASE),) diff --git a/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c b/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c index 80d2fa09b..39f2d29e0 100644 --- a/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c +++ b/v4l2-apps/lib/libv4l/libv4l1/libv4l1.c @@ -59,6 +59,7 @@ #include <linux/videodev.h> #include <linux/videodev2.h> #include <libv4l2.h> +#include "libv4l1.h" #include "libv4l1-priv.h" #define V4L1_SUPPORTS_ENUMINPUT 0x01 @@ -582,7 +583,7 @@ int v4l1_ioctl (int fd, unsigned long int request, ...) input2.index = chan->channel; result = v4l2_ioctl(fd, VIDIOC_ENUMINPUT, &input2); if (result == 0) { - snprintf(chan->name, sizeof(chan->name), "%s", input2.name); + snprintf(chan->name, sizeof(chan->name), "%s", (char*)input2.name); if (input2.type == V4L2_INPUT_TYPE_TUNER) { chan->tuners = 1; chan->type = VIDEO_TYPE_TV; diff --git a/v4l2-apps/lib/libv4l/libv4l1/log.c b/v4l2-apps/lib/libv4l/libv4l1/log.c index cccc3e6d0..74ce0f20b 100644 --- a/v4l2-apps/lib/libv4l/libv4l1/log.c +++ b/v4l2-apps/lib/libv4l/libv4l1/log.c @@ -25,6 +25,7 @@ #include <asm/types.h> /* end broken header workaround includes */ #include <linux/videodev.h> +#include "libv4l1-priv.h" #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -92,9 +93,9 @@ void v4l1_log_ioctl(unsigned long int request, void *arg, int result) break; case VIDIOCGWIN: case VIDIOCSWIN: - fprintf(v4l1_log_file,"width\t%d\n", + fprintf(v4l1_log_file,"width\t%u\n", ((struct video_window *)arg)->width); - fprintf(v4l1_log_file,"height\t%d\n", + fprintf(v4l1_log_file,"height\t%u\n", ((struct video_window *)arg)->height); break; @@ -115,7 +116,7 @@ void v4l1_log_ioctl(unsigned long int request, void *arg, int result) fprintf(v4l1_log_file,"palette %d\n",( (int)((struct video_picture*)arg)->palette) ); break; - case VIDIOCCAPTURE: fprintf(v4l1_log_file,"on/of? %d\n", *((int *)arg) ); + case VIDIOCCAPTURE: fprintf(v4l1_log_file,"on/off? %d\n", *((int *)arg) ); break; case VIDIOCSYNC: fprintf(v4l1_log_file,"sync %d\n", *((int *)arg) ); diff --git a/v4l2-apps/lib/libv4l/libv4l1/v4l1compat.c b/v4l2-apps/lib/libv4l/libv4l1/v4l1compat.c index f1134fe3b..e4293d2f9 100644 --- a/v4l2-apps/lib/libv4l/libv4l1/v4l1compat.c +++ b/v4l2-apps/lib/libv4l/libv4l1/v4l1compat.c @@ -26,12 +26,21 @@ #include <fcntl.h> #include <libv4l1.h> +#include <sys/ioctl.h> +#include <sys/mman.h> + /* Check that open/read/mmap is not a define */ #if defined open || defined read || defined mmap #error open/read/mmap is a prepocessor macro !! #endif -int open (const char *file, int oflag, ...) +#if __GNUC__ >= 4 +#define LIBV4L_PUBLIC __attribute__ ((visibility("default"))) +#else +#define LIBV4L_PUBLIC +#endif + +LIBV4L_PUBLIC int open (const char *file, int oflag, ...) { int fd; @@ -52,7 +61,7 @@ int open (const char *file, int oflag, ...) return fd; } -int open64 (const char *file, int oflag, ...) +LIBV4L_PUBLIC int open64 (const char *file, int oflag, ...) { int fd; @@ -73,16 +82,16 @@ int open64 (const char *file, int oflag, ...) return fd; } -int close(int fd) { +LIBV4L_PUBLIC int close(int fd) { return v4l1_close(fd); } -int dup(int fd) +LIBV4L_PUBLIC int dup(int fd) { return v4l1_dup(fd); } -int ioctl (int fd, unsigned long int request, ...) +LIBV4L_PUBLIC int ioctl (int fd, unsigned long int request, ...) { void *arg; va_list ap; @@ -94,24 +103,25 @@ int ioctl (int fd, unsigned long int request, ...) return v4l1_ioctl (fd, request, arg); } -ssize_t read(int fd, void* buffer, size_t n) +LIBV4L_PUBLIC ssize_t read(int fd, void* buffer, size_t n) { return v4l1_read (fd, buffer, n); } -void *mmap(void *start, size_t length, int prot, int flags, int fd, +LIBV4L_PUBLIC void *mmap(void *start, size_t length, int prot, int flags, int fd, __off_t offset) { return v4l1_mmap(start, length, prot, flags, fd, offset); } -void *mmap64(void *start, size_t length, int prot, int flags, int fd, +LIBV4L_PUBLIC void *mmap64(void *start, size_t length, int prot, int flags, int fd, __off64_t offset) { return v4l1_mmap(start, length, prot, flags, fd, offset); } -int munmap(void *start, size_t length) +LIBV4L_PUBLIC int munmap(void *start, size_t length) { return v4l1_munmap(start, length); } + diff --git a/v4l2-apps/lib/libv4l/libv4l2/Makefile b/v4l2-apps/lib/libv4l/libv4l2/Makefile index d8ac01c34..648d27c0c 100644 --- a/v4l2-apps/lib/libv4l/libv4l2/Makefile +++ b/v4l2-apps/lib/libv4l/libv4l2/Makefile @@ -1,7 +1,7 @@ -CPPFLAGS = -I../include -I../../../../linux/include +override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden CFLAGS := -g -O1 -CFLAGS += -Wall -W -Wno-unused -Wpointer-arith -Wstrict-prototypes +CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes LIBS = -lpthread @@ -17,7 +17,7 @@ else V4L2_LIB = libv4l2.so V4L2_OBJS += ../libv4lconvert/libv4lconvert.so TARGETS += $(V4L2CONVERT) -CPPFLAGS += -fPIC +override CPPFLAGS += -fPIC endif ifeq ($(LIB_RELEASE),) diff --git a/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c b/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c index a40ab4ffe..7029f69c3 100644 --- a/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c +++ b/v4l2-apps/lib/libv4l/libv4l2/libv4l2.c @@ -252,23 +252,54 @@ static int v4l2_queue_read_buffer(int index, int buffer_index) return 0; } -static int v4l2_dequeue_read_buffer(int index, int *bytesused) +static int v4l2_dequeue_and_convert(int index, struct v4l2_buffer *buf, + unsigned char *dest, int dest_size) { - int result; - struct v4l2_buffer buf; + const int max_tries = 10; + int result, tries = max_tries; - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, &buf))) { - int saved_err = errno; - V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno)); - errno = saved_err; + /* Make sure we have the real v4l2 buffers mapped */ + if ((result = v4l2_map_buffers(index))) return result; + + do { + if ((result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf))) { + int saved_err = errno; + V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno)); + errno = saved_err; + return result; + } + + devices[index].frame_queued &= ~(1 << buf->index); + + result = v4lconvert_convert(devices[index].convert, + &devices[index].src_fmt, &devices[index].dest_fmt, + devices[index].frame_pointers[buf->index], + buf->bytesused, dest ? dest : (devices[index].convert_mmap_buf + + buf->index * V4L2_FRAME_BUF_SIZE), dest_size); + + if (result < 0) { + int saved_err = errno; + + if(errno == EAGAIN) + V4L2_LOG("warning error while converting frame data: %s\n", + v4lconvert_get_error_message(devices[index].convert)); + else + V4L2_LOG_ERR("converting / decoding frame data: %s\n", + v4lconvert_get_error_message(devices[index].convert)); + + v4l2_queue_read_buffer(index, buf->index); + errno = saved_err; + } + tries--; + } while (result < 0 && errno == EAGAIN && tries); + + if (result < 0 && errno == EAGAIN) { + V4L2_LOG_ERR("got %d consecutive frame decode errors, last error: %s\n", + max_tries, v4lconvert_get_error_message(devices[index].convert)); } - devices[index].frame_queued &= ~(1 << buf.index); - *bytesused = buf.bytesused; - return buf.index; + return result; } static int v4l2_queue_read_buffers(int index) @@ -614,7 +645,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) is_capture_request = 1; break; case VIDIOC_ENUM_FMT: - if (((struct v4l2_fmtdesc *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (((struct v4l2_fmtdesc *)arg)->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && + (devices[index].flags & V4L2_ENABLE_ENUM_FMT_EMULATION)) is_capture_request = 1; break; case VIDIOC_TRY_FMT: @@ -663,9 +695,8 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) if (stream_needs_locking) pthread_mutex_lock(&devices[index].stream_lock); - converting = devices[index].src_fmt.fmt.pix.pixelformat != - devices[index].dest_fmt.fmt.pix.pixelformat; - + converting = v4lconvert_needs_conversion(devices[index].convert, + &devices[index].src_fmt, &devices[index].dest_fmt); switch (request) { case VIDIOC_QUERYCAP: @@ -815,15 +846,16 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) if ((result = v4l2_deactivate_read_stream(index))) break; - result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf); - if (result) { - V4L2_LOG_ERR("dequeing buffer: %s\n", strerror(errno)); + if (!converting) { + result = syscall(SYS_ioctl, devices[index].fd, VIDIOC_DQBUF, buf); + if (result) { + int saved_err = errno; + V4L2_LOG_ERR("dequeuing buf: %s\n", strerror(errno)); + errno = saved_err; + } break; } - if (!converting) - break; - /* An application can do a DQBUF before mmap-ing in the buffer, but we need the buffer _now_ to write our converted data to it! */ @@ -844,23 +876,9 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) } } - /* Make sure we have the real v4l2 buffers mapped before trying to - read from them */ - if ((result = v4l2_map_buffers(index))) - break; - - result = v4lconvert_convert(devices[index].convert, - &devices[index].src_fmt, &devices[index].dest_fmt, - devices[index].frame_pointers[buf->index], - buf->bytesused, - devices[index].convert_mmap_buf + - buf->index * V4L2_FRAME_BUF_SIZE, - V4L2_FRAME_BUF_SIZE); - if (result < 0) { - V4L2_LOG_ERR("converting / decoding frame data: %s\n", - v4lconvert_get_error_message(devices[index].convert)); + result = v4l2_dequeue_and_convert(index, buf, 0, V4L2_FRAME_BUF_SIZE); + if (result < 0) break; - } buf->bytesused = result; buf->m.offset = V4L2_MMAP_OFFSET_MAGIC | buf->index; @@ -901,22 +919,23 @@ int v4l2_ioctl (int fd, unsigned long int request, ...) } -ssize_t v4l2_read (int fd, void* buffer, size_t n) +ssize_t v4l2_read (int fd, void* dest, size_t n) { ssize_t result; - int index, bytesused = 0, frame_index; + int index; + struct v4l2_buffer buf; if ((index = v4l2_get_index(fd)) == -1) - return syscall(SYS_read, fd, buffer, n); + return syscall(SYS_read, fd, dest, n); pthread_mutex_lock(&devices[index].stream_lock); /* When not converting and the device supports read let the kernel handle it */ if ((devices[index].flags & V4L2_SUPPORTS_READ) && - devices[index].src_fmt.fmt.pix.pixelformat == - devices[index].dest_fmt.fmt.pix.pixelformat) { - result = syscall(SYS_read, fd, buffer, n); + !v4lconvert_needs_conversion(devices[index].convert, + &devices[index].src_fmt, &devices[index].dest_fmt)) { + result = syscall(SYS_read, fd, dest, n); goto leave; } @@ -931,26 +950,12 @@ ssize_t v4l2_read (int fd, void* buffer, size_t n) goto leave; } - if ((frame_index = v4l2_dequeue_read_buffer(index, &bytesused)) < 0) { - result = -1; - goto leave; - } - - /* ensure buffers are mapped before using them (they could have been - unmapped by a s_fmt ioctl) */ - if ((result = v4l2_map_buffers(index))) - goto leave; - - result = v4lconvert_convert(devices[index].convert, - &devices[index].src_fmt, &devices[index].dest_fmt, - devices[index].frame_pointers[frame_index], bytesused, - buffer, n); - - v4l2_queue_read_buffer(index, frame_index); + buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + buf.memory = V4L2_MEMORY_MMAP; + result = v4l2_dequeue_and_convert(index, &buf, dest, n); - if (result < 0) - V4L2_LOG_ERR("converting / decoding frame data: %s\n", - v4lconvert_get_error_message(devices[index].convert)); + if (result >= 0) + v4l2_queue_read_buffer(index, buf.index); leave: pthread_mutex_unlock(&devices[index].stream_lock); @@ -988,8 +993,8 @@ void *v4l2_mmap(void *start, size_t length, int prot, int flags, int fd, buffer_index = offset & 0xff; if (buffer_index >= devices[index].no_frames || /* Got magic offset and not converting ?? */ - devices[index].src_fmt.fmt.pix.pixelformat == - devices[index].dest_fmt.fmt.pix.pixelformat) { + !v4lconvert_needs_conversion(devices[index].convert, + &devices[index].src_fmt, &devices[index].dest_fmt)) { errno = EINVAL; result = MAP_FAILED; goto leave; diff --git a/v4l2-apps/lib/libv4l/libv4l2/log.c b/v4l2-apps/lib/libv4l/libv4l2/log.c index 05f6c46d7..6237d55ec 100644 --- a/v4l2-apps/lib/libv4l/libv4l2/log.c +++ b/v4l2-apps/lib/libv4l/libv4l2/log.c @@ -25,6 +25,8 @@ #include <asm/types.h> /* end broken header workaround includes */ #include <linux/videodev2.h> +#include "libv4l2.h" +#include "libv4l2-priv.h" #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) @@ -116,7 +118,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) int pixfmt = fmt->fmt.pix.pixelformat; if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - fprintf(v4l2_log_file, " pixelformat: %c%c%c%c %dx%d\n", + fprintf(v4l2_log_file, " pixelformat: %c%c%c%c %ux%u\n", pixfmt & 0xff, (pixfmt >> 8) & 0xff, (pixfmt >> 16) & 0xff, @@ -136,7 +138,7 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result) struct v4l2_requestbuffers *req = arg; fprintf(v4l2_log_file, " count: %u type: %d memory: %d\n", - req->count, req->type, req->memory); + req->count, (int)req->type, (int)req->memory); } break; } diff --git a/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c b/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c index f312828c6..e8756f338 100644 --- a/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c +++ b/v4l2-apps/lib/libv4l/libv4l2/v4l2convert.c @@ -27,6 +27,8 @@ #include <syscall.h> #include <fcntl.h> #include <string.h> +#include <sys/ioctl.h> +#include <sys/mman.h> /* These headers are not needed by us, but by linux/videodev2.h, which is broken on some systems and doesn't include them itself :( */ #include <sys/time.h> @@ -41,7 +43,13 @@ #error open/read/mmap is a prepocessor macro !! #endif -int open (const char *file, int oflag, ...) +#if __GNUC__ >= 4 +#define LIBV4L_PUBLIC __attribute__ ((visibility("default"))) +#else +#define LIBV4L_PUBLIC +#endif + +LIBV4L_PUBLIC int open (const char *file, int oflag, ...) { int fd; struct v4l2_capability cap; @@ -84,7 +92,7 @@ int open (const char *file, int oflag, ...) return fd; } -int open64(const char *file, int oflag, ...) +LIBV4L_PUBLIC int open64(const char *file, int oflag, ...) { int fd; @@ -107,17 +115,17 @@ int open64(const char *file, int oflag, ...) return fd; } -int close(int fd) +LIBV4L_PUBLIC int close(int fd) { return v4l2_close(fd); } -int dup(int fd) +LIBV4L_PUBLIC int dup(int fd) { return v4l2_dup(fd); } -int ioctl (int fd, unsigned long int request, ...) +LIBV4L_PUBLIC int ioctl (int fd, unsigned long int request, ...) { void *arg; va_list ap; @@ -129,24 +137,25 @@ int ioctl (int fd, unsigned long int request, ...) return v4l2_ioctl (fd, request, arg); } -ssize_t read (int fd, void* buffer, size_t n) +LIBV4L_PUBLIC ssize_t read (int fd, void* buffer, size_t n) { return v4l2_read (fd, buffer, n); } -void *mmap(void *start, size_t length, int prot, int flags, int fd, +LIBV4L_PUBLIC void *mmap(void *start, size_t length, int prot, int flags, int fd, __off_t offset) { return v4l2_mmap(start, length, prot, flags, fd, offset); } -void *mmap64(void *start, size_t length, int prot, int flags, int fd, +LIBV4L_PUBLIC void *mmap64(void *start, size_t length, int prot, int flags, int fd, __off64_t offset) { return v4l2_mmap(start, length, prot, flags, fd, offset); } -int munmap(void *start, size_t length) +LIBV4L_PUBLIC int munmap(void *start, size_t length) { return v4l2_munmap(start, length); } + diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/Makefile b/v4l2-apps/lib/libv4l/libv4lconvert/Makefile index c2a5be942..641d19d6e 100644 --- a/v4l2-apps/lib/libv4l/libv4lconvert/Makefile +++ b/v4l2-apps/lib/libv4l/libv4lconvert/Makefile @@ -1,16 +1,16 @@ -CPPFLAGS = -I../include -I../../../../linux/include +override CPPFLAGS += -I../include -I../../../include -fvisibility=hidden CFLAGS := -g -O1 -CFLAGS += -Wall -W -Wno-unused -Wpointer-arith -Wstrict-prototypes +CFLAGS += -Wall -Wno-unused -Wpointer-arith -Wstrict-prototypes -Wmissing-prototypes ifeq ($(LINKTYPE),static) CONVERT_LIB = libv4lconvert.a else CONVERT_LIB = libv4lconvert.so -CPPFLAGS += -fPIC +override CPPFLAGS += -fPIC endif -CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o pac207.o \ +CONVERT_OBJS = libv4lconvert.o tinyjpeg.o sn9c10x.o pac207.o flip.o \ jidctflt.o spca561-decompress.o rgbyuv.o spca501.o bayer.o TARGETS = $(CONVERT_LIB) libv4lconvert.pc INCLUDES = ../include/libv4lconvert.h diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/flip.c b/v4l2-apps/lib/libv4l/libv4lconvert/flip.c new file mode 100644 index 000000000..cd3468a89 --- /dev/null +++ b/v4l2-apps/lib/libv4l/libv4lconvert/flip.c @@ -0,0 +1,107 @@ +/* + +# RGB / YUV flip/rotate routines + +# (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "libv4lconvert-priv.h" + +void v4lconvert_rotate180_rgbbgr24(const unsigned char *src, unsigned char *dst, + int width, int height) +{ + int i; + + src += 3 * width * height - 3; + + for (i = 0; i < width * height; i++) { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + dst += 3; + src -= 3; + } +} + +void v4lconvert_rotate180_yuv420(const unsigned char *src, unsigned char *dst, + int width, int height) +{ + int i; + + /* First flip x and y of the Y plane */ + src += width * height - 1; + for (i = 0; i < width * height; i++) + *dst++ = *src--; + + /* Now flip the U plane */ + src += width * height * 5 / 4; + for (i = 0; i < width * height / 4; i++) + *dst++ = *src--; + + /* Last flip the V plane */ + src += width * height / 2; + for (i = 0; i < width * height / 4; i++) + *dst++ = *src--; +} + +void v4lconvert_rotate90_rgbbgr24(const unsigned char *src, unsigned char *dst, + int destwidth, int destheight) +{ + int x, y; +#define srcwidth destheight +#define srcheight destwidth + + for (y = 0; y < destheight; y++) + for (x = 0; x < destwidth; x++) { + int offset = ((srcheight - x - 1) * srcwidth + y) * 3; + *dst++ = src[offset++]; + *dst++ = src[offset++]; + *dst++ = src[offset]; + } +} + +void v4lconvert_rotate90_yuv420(const unsigned char *src, unsigned char *dst, + int destwidth, int destheight) +{ + int x, y; + + /* Y-plane */ + for (y = 0; y < destheight; y++) + for (x = 0; x < destwidth; x++) { + int offset = (srcheight - x - 1) * srcwidth + y; + *dst++ = src[offset]; + } + + /* U-plane */ + src += srcwidth * srcheight; + destwidth /= 2; + destheight /= 2; + for (y = 0; y < destheight; y++) + for (x = 0; x < destwidth; x++) { + int offset = (srcheight - x - 1) * srcwidth + y; + *dst++ = src[offset]; + } + + /* V-plane */ + src += srcwidth * srcheight; + for (y = 0; y < destheight; y++) + for (x = 0; x < destwidth; x++) { + int offset = (srcheight - x - 1) * srcwidth + y; + *dst++ = src[offset]; + } +} diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/jidctflt.c b/v4l2-apps/lib/libv4l/libv4lconvert/jidctflt.c index ba70309c9..532abc7ea 100644 --- a/v4l2-apps/lib/libv4l/libv4lconvert/jidctflt.c +++ b/v4l2-apps/lib/libv4l/libv4lconvert/jidctflt.c @@ -80,7 +80,7 @@ #define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) -#if defined(__GNUC__) && (defined(__i686__)) // || defined(__x86_64__)) +#if defined(__GNUC__) && (defined(__i686__) || defined(__x86_64__)) static inline unsigned char descale_and_clamp(int x, int shift) { @@ -92,7 +92,7 @@ static inline unsigned char descale_and_clamp(int x, int shift) "\tcmpl %4,%1\n" "\tcmovg %4,%1\n" : "=r"(x) - : "0"(x), "Ic"((unsigned char)shift), "ir"(1UL<<(shift-1)), "r" (0xff), "r" (0) + : "0"(x), "Ic"((unsigned char)shift), "ir"(1U<<(shift-1)), "r" (0xff), "r" (0) ); return x; } diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h index bdf847186..915c33283 100644 --- a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h +++ b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert-priv.h @@ -43,6 +43,10 @@ #define V4L2_PIX_FMT_PAC207 v4l2_fourcc('P','2','0','7') #endif +#ifndef V4L2_PIX_FMT_PJPG +#define V4L2_PIX_FMT_PJPG v4l2_fourcc('P', 'J', 'P', 'G') +#endif + #ifndef V4L2_PIX_FMT_SGBRG8 #define V4L2_PIX_FMT_SGBRG8 v4l2_fourcc('G','B','R','G') #endif @@ -61,15 +65,21 @@ snprintf(data->error_msg, V4LCONVERT_ERROR_MSG_SIZE, \ "v4l-convert: error " __VA_ARGS__) +#define V4LCONVERT_UPSIDE_DOWN 0x01 struct v4lconvert_data { int fd; + int flags; /* bitfield */ int supported_src_formats; /* bitfield */ unsigned int no_formats; char error_msg[V4LCONVERT_ERROR_MSG_SIZE]; struct jdec_private *jdec; }; +struct v4lconvert_flags_info { + const char *card; + int flags; +}; void v4lconvert_yuv420_to_rgb24(const unsigned char *src, unsigned char *dst, int width, int height); @@ -107,4 +117,16 @@ void v4lconvert_bayer_to_bgr24(const unsigned char *bayer, void v4lconvert_bayer_to_yuv420(const unsigned char *bayer, unsigned char *yuv, int width, int height, unsigned int pixfmt); +void v4lconvert_rotate90_rgbbgr24(const unsigned char *src, unsigned char *dst, + int destwidth, int destheight); + +void v4lconvert_rotate90_yuv420(const unsigned char *src, unsigned char *dst, + int destwidth, int destheight); + +void v4lconvert_rotate180_rgbbgr24(const unsigned char *src, unsigned char *dst, + int width, int height); + +void v4lconvert_rotate180_yuv420(const unsigned char *src, unsigned char *dst, + int width, int height); + #endif diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c index 4c9e67d52..4b48bfac4 100644 --- a/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c +++ b/v4l2-apps/lib/libv4l/libv4lconvert/libv4lconvert.c @@ -48,17 +48,26 @@ static const unsigned int supported_src_pixfmts[] = { V4L2_PIX_FMT_SPCA561, V4L2_PIX_FMT_SN9C10X, V4L2_PIX_FMT_PAC207, + V4L2_PIX_FMT_PJPG, }; static const unsigned int supported_dst_pixfmts[] = { SUPPORTED_DST_PIXFMTS }; +/* List of cams which need special flags */ +static const struct v4lconvert_flags_info v4lconvert_flags[] = { + { "USB Camera (0471:0325)", V4LCONVERT_UPSIDE_DOWN }, /* SPC200NC */ + { "USB Camera (0471:0326)", V4LCONVERT_UPSIDE_DOWN }, /* SPC300NC */ + { "SPC 200NC ", V4LCONVERT_UPSIDE_DOWN }, + { "SPC 300NC ", V4LCONVERT_UPSIDE_DOWN }, +}; struct v4lconvert_data *v4lconvert_create(int fd) { int i, j; struct v4lconvert_data *data = calloc(1, sizeof(struct v4lconvert_data)); + struct v4l2_capability cap; if (!data) return NULL; @@ -84,6 +93,15 @@ struct v4lconvert_data *v4lconvert_create(int fd) data->no_formats = i; + /* Check if this cam has any special flags */ + if (syscall(SYS_ioctl, fd, VIDIOC_QUERYCAP, &cap) == 0) { + for (i = 0; i < ARRAY_SIZE(v4lconvert_flags); i++) + if (!strcmp((const char *)v4lconvert_flags[i].card, (char *)cap.card)) { + data->flags = v4lconvert_flags[i].flags; + break; + } + } + return data; } @@ -214,17 +232,42 @@ int v4lconvert_try_format(struct v4lconvert_data *data, return 0; } +/* Is conversion necessary ? */ +int v4lconvert_needs_conversion(struct v4lconvert_data *data, + const struct v4l2_format *src_fmt, /* in */ + const struct v4l2_format *dest_fmt) /* in */ +{ + int i; + + if(memcmp(src_fmt, dest_fmt, sizeof(*src_fmt))) + return 1; /* Formats differ */ + + if (!(data->flags & V4LCONVERT_UPSIDE_DOWN)) + return 0; /* Formats identical and we don't need flip */ + + /* Formats are identical, but we need flip, do we support the dest_fmt? */ + for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) + if (supported_dst_pixfmts[i] == dest_fmt->fmt.pix.pixelformat) + break; + + if (i == ARRAY_SIZE(supported_dst_pixfmts)) + return 0; /* Needs flip but we cannot do it :( */ + else + return 1; /* Needs flip and thus conversion */ +} + int v4lconvert_convert(struct v4lconvert_data *data, const struct v4l2_format *src_fmt, /* in */ const struct v4l2_format *dest_fmt, /* in */ - unsigned char *src, int src_size, unsigned char *dest, int dest_size) + unsigned char *src, int src_size, unsigned char *_dest, int dest_size) { unsigned int header_width, header_height; - int result, needed; + int result, needed, rotate = 0, jpeg_flags = TINYJPEG_FLAGS_MJPEG_TABLE; unsigned char *components[3]; + unsigned char *dest = _dest; /* Special case when no conversion is needed */ - if(!memcmp(src_fmt, dest_fmt, sizeof(*src_fmt))) { + if (!v4lconvert_needs_conversion(data, src_fmt, dest_fmt)) { int to_copy = MIN(dest_size, src_size); memcpy(dest, src, to_copy); return to_copy; @@ -251,7 +294,15 @@ int v4lconvert_convert(struct v4lconvert_data *data, return -1; } + if (data->flags & V4LCONVERT_UPSIDE_DOWN) { + rotate = 180; + dest = alloca(needed); + } + switch (src_fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_PJPG: + jpeg_flags |= TINYJPEG_FLAGS_PIXART_JPEG; + /* Fall through */ case V4L2_PIX_FMT_MJPEG: case V4L2_PIX_FMT_JPEG: if (!data->jdec) { @@ -262,9 +313,7 @@ int v4lconvert_convert(struct v4lconvert_data *data, return -1; } } - tinyjpeg_set_flags(data->jdec, - (src_fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)? - TINYJPEG_FLAGS_MJPEG_TABLE : 0); + tinyjpeg_set_flags(data->jdec, jpeg_flags); if (tinyjpeg_parse_header(data->jdec, src, src_size)) { V4LCONVERT_ERR("parsing JPEG header: %s\n", tinyjpeg_get_errorstring(data->jdec)); @@ -273,13 +322,22 @@ int v4lconvert_convert(struct v4lconvert_data *data, } tinyjpeg_get_size(data->jdec, &header_width, &header_height); - if (header_width != dest_fmt->fmt.pix.width || header_height != dest_fmt->fmt.pix.height) { - V4LCONVERT_ERR("unexpected width / height in JPEG header\n"); - V4LCONVERT_ERR("expected: %dx%d, header: %ux%u\n", - dest_fmt->fmt.pix.width, dest_fmt->fmt.pix.height, - header_width, header_height); - errno = EIO; - return -1; + if (header_width != dest_fmt->fmt.pix.width || + header_height != dest_fmt->fmt.pix.height) { + /* Check for (pixart) rotated JPEG */ + if (header_width == dest_fmt->fmt.pix.height || + header_height == dest_fmt->fmt.pix.width) { + if (!rotate) + dest = alloca(needed); + rotate += 90; + } else { + V4LCONVERT_ERR("unexpected width / height in JPEG header" + "expected: %ux%u, header: %ux%u\n", + dest_fmt->fmt.pix.width, dest_fmt->fmt.pix.height, + header_width, header_height); + errno = EIO; + return -1; + } } components[0] = dest; @@ -303,13 +361,24 @@ int v4lconvert_convert(struct v4lconvert_data *data, break; } - /* If the JPEG header checked out ok and we get an error during actual - decompression, log the error, but don't return an errorcode to the - application, so that the user gets what we managed to decompress */ - if (result) - fprintf(stderr, "libv4lconvert: Error decompressing JPEG: %s", - tinyjpeg_get_errorstring(data->jdec)); - + if (result) { + /* Pixart webcam's seem to regulary generate corrupt frames, which + are best thrown away to avoid flashes in the video stream. Tell + the upper layer this is an intermediate fault and it should try + again with a new buffer by setting errno to EAGAIN */ + if (src_fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_PJPG) { + V4LCONVERT_ERR("Error decompressing JPEG: %s", + tinyjpeg_get_errorstring(data->jdec)); + errno = EAGAIN; + return -1; + } else { + /* If the JPEG header checked out ok and we get an error during actual + decompression, log the error, but don't return an errorcode to the + application, so that the user gets what we managed to decompress */ + fprintf(stderr, "libv4lconvert: Error decompressing JPEG: %s", + tinyjpeg_get_errorstring(data->jdec)); + } + } break; case V4L2_PIX_FMT_SBGGR8: @@ -387,7 +456,7 @@ int v4lconvert_convert(struct v4lconvert_data *data, case V4L2_PIX_FMT_SN9C10X: v4lconvert_decode_sn9c10x(src, tmpbuf, dest_fmt->fmt.pix.width, dest_fmt->fmt.pix.height); - bayer_fmt = V4L2_PIX_FMT_SGBRG8; + bayer_fmt = V4L2_PIX_FMT_SBGGR8; break; case V4L2_PIX_FMT_PAC207: v4lconvert_decode_pac207(src, tmpbuf, dest_fmt->fmt.pix.width, @@ -455,6 +524,45 @@ int v4lconvert_convert(struct v4lconvert_data *data, return -1; } + /* Note when rotating dest is our temporary buffer to which our conversion + was done and _dest is the real dest! If the formats are identical no + conversion has been done! */ + if (rotate && dest_fmt->fmt.pix.pixelformat == src_fmt->fmt.pix.pixelformat) + dest = src; + + switch (rotate) { + case 0: + break; + case 90: + switch (dest_fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + v4lconvert_rotate90_rgbbgr24(dest, _dest, dest_fmt->fmt.pix.width, + dest_fmt->fmt.pix.height); + break; + case V4L2_PIX_FMT_YUV420: + v4lconvert_rotate90_yuv420(dest, _dest, dest_fmt->fmt.pix.width, + dest_fmt->fmt.pix.height); + break; + } + break; + case 180: + switch (dest_fmt->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + v4lconvert_rotate180_rgbbgr24(dest, _dest, dest_fmt->fmt.pix.width, + dest_fmt->fmt.pix.height); + break; + case V4L2_PIX_FMT_YUV420: + v4lconvert_rotate180_yuv420(dest, _dest, dest_fmt->fmt.pix.width, + dest_fmt->fmt.pix.height); + break; + } + break; + default: + printf("FIXME add %d degrees rotation\n", rotate); + } + return needed; } diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/pac207.c b/v4l2-apps/lib/libv4l/libv4lconvert/pac207.c index 4887c25ee..97ef4ebc0 100644 --- a/v4l2-apps/lib/libv4l/libv4lconvert/pac207.c +++ b/v4l2-apps/lib/libv4l/libv4lconvert/pac207.c @@ -38,7 +38,7 @@ static struct { signed char val; } table[256]; -void init_pixart_decoder(void) +static void init_pixart_decoder(void) { int i; int is_abs, val, len; diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c b/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c index 742dd06ce..883d62330 100644 --- a/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c +++ b/v4l2-apps/lib/libv4l/libv4lconvert/rgbyuv.c @@ -20,6 +20,8 @@ */ +#include "libv4lconvert-priv.h" + #define RGB2YUV(r,g,b,y,u,v) \ (y) = (( 8453*(r) + 16594*(g) + 3223*(b) + 524288) >> 15); \ (u) = (( -4878*(r) - 9578*(g) + 14456*(b) + 4210688) >> 15); \ diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/sn9c10x.c b/v4l2-apps/lib/libv4l/libv4lconvert/sn9c10x.c index 98a513378..4ea526d49 100644 --- a/v4l2-apps/lib/libv4l/libv4lconvert/sn9c10x.c +++ b/v4l2-apps/lib/libv4l/libv4lconvert/sn9c10x.c @@ -50,7 +50,7 @@ static int sonix_unknown = 0; present at the MSB of byte x. */ -void sonix_decompress_init(void) +static void sonix_decompress_init(void) { int i; int is_abs, val, len, unk; diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/spca561-decompress.c b/v4l2-apps/lib/libv4l/libv4lconvert/spca561-decompress.c index 802345af0..01eed4ec5 100644 --- a/v4l2-apps/lib/libv4l/libv4lconvert/spca561-decompress.c +++ b/v4l2-apps/lib/libv4l/libv4lconvert/spca561-decompress.c @@ -28,6 +28,7 @@ * but it might work with other spca561 cameras */ #include <string.h> +#include "libv4lconvert-priv.h" /*fixme: not reentrant */ static unsigned int bit_bucket; diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.c b/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.c index 5c3b4e26d..fc9efbeb2 100644 --- a/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.c +++ b/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.c @@ -214,6 +214,28 @@ static const unsigned char val_ac_chrominance[] = 0xf9, 0xfa }; +const unsigned char pixart_quantization[][64] = { + { + 0x07, 0x07, 0x08, 0x0a, 0x09, 0x07, 0x0d, 0x0b, + 0x0c, 0x0d, 0x11, 0x10, 0x0f, 0x12, 0x17, 0x27, + 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, + }, + { + 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, + }, +}; /* * 4 functions to manage the stream @@ -246,7 +268,7 @@ static const unsigned char val_ac_chrominance[] = unsigned char c; \ if (stream >= priv->stream_end) { \ snprintf(priv->error_string, sizeof(priv->error_string), \ - "fill_nbits error: need %d more bits\n", \ + "fill_nbits error: need %u more bits\n", \ nbits_wanted - nbits_in_reservoir); \ longjmp(priv->jump_state, -EIO); \ } \ @@ -288,6 +310,74 @@ static const unsigned char val_ac_chrominance[] = } while(0); +/* Special Pixart versions of the *_nbits functions, these remove the special + ff ff ff xx sequences pixart cams insert from the bitstream */ +#define pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) \ +do { \ + while (nbits_in_reservoir<nbits_wanted) \ + { \ + unsigned char c; \ + if (stream >= priv->stream_end) { \ + snprintf(priv->error_string, sizeof(priv->error_string), \ + "fill_nbits error: need %u more bits\n", \ + nbits_wanted - nbits_in_reservoir); \ + longjmp(priv->jump_state, -EIO); \ + } \ + c = *stream++; \ + reservoir <<= 8; \ + if (c == 0xff) { \ + switch (stream[0]) { \ + case 0x00: \ + stream++; \ + break; \ + case 0xd9: /* EOF marker */ \ + stream++; \ + if (stream != priv->stream_end) { \ + snprintf(priv->error_string, sizeof(priv->error_string), \ + "Pixart JPEG error: premature EOF\n"); \ + longjmp(priv->jump_state, -EIO); \ + } \ + break; \ + case 0xff: \ + if (stream[1] == 0xff && (stream[2] < 7 || stream[2] == 0xff)) { \ + stream += 3; \ + c = *stream++; \ + break; \ + } \ + /* Error fall through */ \ + default: \ + snprintf(priv->error_string, sizeof(priv->error_string), \ + "Pixart JPEG error: invalid JPEG marker: 0xff 0x%02x 0x%02x 0x%02x\n", \ + (unsigned int)stream[0], (unsigned int)stream[1], \ + (unsigned int)stream[2]); \ + longjmp(priv->jump_state, -EIO); \ + } \ + } \ + reservoir |= c; \ + nbits_in_reservoir+=8; \ + } \ +} while(0); + +/* Signed version !!!! */ +#define pixart_get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) \ +do { \ + pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \ + result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \ + nbits_in_reservoir -= (nbits_wanted); \ + reservoir &= ((1U<<nbits_in_reservoir)-1); \ + if ((unsigned int)result < (1UL<<((nbits_wanted)-1))) \ + result += (0xFFFFFFFFUL<<(nbits_wanted))+1; \ +} while(0); + +#define pixart_look_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) \ +do { \ + pixart_fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \ + result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \ +} while(0); + +/* Note skip_nbits is identical for both */ + + #define be16_to_cpu(x) (((x)[0]<<8)|(x)[1]) static void resync(struct jdec_private *priv); @@ -334,9 +424,50 @@ static int get_next_huffman_code(struct jdec_private *priv, struct huffman_table slowtable+=2; } } + snprintf(priv->error_string, sizeof(priv->error_string), + "unknown huffman code: %08x\n", (unsigned int)hcode); + longjmp(priv->jump_state, -EIO); return 0; } +/* identical as above but with *_nbits replaced with pixart_*_nbits */ +static int pixart_get_next_huffman_code(struct jdec_private *priv, + struct huffman_table *huffman_table) +{ + int value, hcode; + unsigned int extra_nbits, nbits; + uint16_t *slowtable; + + pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, HUFFMAN_HASH_NBITS, hcode); + value = huffman_table->lookup[hcode]; + if (value >= 0) + { + unsigned int code_size = huffman_table->code_size[value]; + skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, code_size); + return value; + } + + /* Decode more bits each time ... */ + for (extra_nbits=0; extra_nbits<16-HUFFMAN_HASH_NBITS; extra_nbits++) + { + nbits = HUFFMAN_HASH_NBITS + 1 + extra_nbits; + + pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits, hcode); + slowtable = huffman_table->slowtable[extra_nbits]; + /* Search if the code is in this array */ + while (slowtable[0]) { + if (slowtable[0] == hcode) { + skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits); + return slowtable[1]; + } + slowtable+=2; + } + } + snprintf(priv->error_string, sizeof(priv->error_string), + "unknown huffman code: %08x\n", (unsigned int)hcode); + longjmp(priv->jump_state, -EIO); + return 0; +} @@ -388,15 +519,84 @@ static void process_Huffman_data_unit(struct jdec_private *priv, int component) else { j += count_0; /* skip count_0 zeroes */ - get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]); - j++; + if (j < 64) { + get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]); + j++; + } } } + if (j > 64) { + snprintf(priv->error_string, sizeof(priv->error_string), + "error: more then 63 AC components (%d) in huffman unit\n", (int)j); + longjmp(priv->jump_state, -EIO); + } + for (j = 0; j < 64; j++) c->DCT[j] = DCT[zigzag[j]]; } +/* identical as above both with *_nbits replaced with pixart_*_nbits */ +static void pixart_process_Huffman_data_unit(struct jdec_private *priv, int component) +{ + unsigned char j; + unsigned int huff_code; + unsigned char size_val, count_0; + + struct component *c = &priv->component_infos[component]; + short int DCT[64]; + + /* Initialize the DCT coef table */ + memset(DCT, 0, sizeof(DCT)); + + /* DC coefficient decoding */ + huff_code = pixart_get_next_huffman_code(priv, c->DC_table); + if (huff_code) { + pixart_get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, huff_code, DCT[0]); + DCT[0] += c->previous_DC; + c->previous_DC = DCT[0]; + } else { + DCT[0] = c->previous_DC; + } + + + /* AC coefficient decoding */ + j = 1; + while (j<64) + { + huff_code = pixart_get_next_huffman_code(priv, c->AC_table); + + size_val = huff_code & 0xF; + count_0 = huff_code >> 4; + + if (size_val == 0) + { /* RLE */ + if (count_0 == 0) + break; /* EOB found, go out */ + else if (count_0 == 0xF) + j += 16; /* skip 16 zeros */ + } + else + { + j += count_0; /* skip count_0 zeroes */ + if (j < 64 ) { + pixart_get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]); + j++; + } + } + } + + if (j > 64) { + snprintf(priv->error_string, sizeof(priv->error_string), + "error: more then 63 AC components (%d) in huffman unit\n", (int)j); + longjmp(priv->jump_state, -EIO); + } + + for (j = 0; j < 64; j++) + c->DCT[j] = DCT[zigzag[j]]; +} + + /* * Takes two array of bits, and build the huffman table for size, and code * @@ -404,12 +604,13 @@ static void process_Huffman_data_unit(struct jdec_private *priv, int component) * code_size will be used to known how many bits this symbol is encoded. * slowtable will be used when the first lookup didn't give the result. */ -static void build_huffman_table(const unsigned char *bits, const unsigned char *vals, struct huffman_table *table) +static int build_huffman_table(struct jdec_private *priv, const unsigned char *bits, const unsigned char *vals, struct huffman_table *table) { unsigned int i, j, code, code_size, val, nbits; unsigned char huffsize[257], *hz; unsigned int huffcode[257], *hc; int next_free_entry; + int slowtable_used[16-HUFFMAN_HASH_NBITS]; /* * Build a temp array @@ -425,7 +626,7 @@ static void build_huffman_table(const unsigned char *bits, const unsigned char * memset(table->lookup, 0xff, sizeof(table->lookup)); for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++) - table->slowtable[i][0] = 0; + slowtable_used[i] = 0; /* Build a temp array * huffcode[X] => code used to write vals[X] @@ -472,32 +673,43 @@ static void build_huffman_table(const unsigned char *bits, const unsigned char * else { /* Perhaps sorting the array will be an optimization */ - uint16_t *slowtable = table->slowtable[code_size-HUFFMAN_HASH_NBITS-1]; - while(slowtable[0]) - slowtable+=2; - slowtable[0] = code; - slowtable[1] = val; - slowtable[2] = 0; - /* TODO: NEED TO CHECK FOR AN OVERFLOW OF THE TABLE */ - } + int slowtable_index = code_size-HUFFMAN_HASH_NBITS-1; + + if (slowtable_used[slowtable_index] == 254) + error("slow Huffman table overflow\n"); + table->slowtable[slowtable_index][slowtable_used[slowtable_index]] + = code; + table->slowtable[slowtable_index][slowtable_used[slowtable_index] + 1] + = val; + slowtable_used[slowtable_index] += 2; + } } + for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++) + table->slowtable[i][slowtable_used[i]] = 0; + + return 0; } -static void build_default_huffman_tables(struct jdec_private *priv) +static int build_default_huffman_tables(struct jdec_private *priv) { if ( (priv->flags & TINYJPEG_FLAGS_MJPEG_TABLE) && priv->default_huffman_table_initialized) - return; + return 0; - build_huffman_table(bits_dc_luminance, val_dc_luminance, &priv->HTDC[0]); - build_huffman_table(bits_ac_luminance, val_ac_luminance, &priv->HTAC[0]); + if (build_huffman_table(priv, bits_dc_luminance, val_dc_luminance, &priv->HTDC[0])) + return -1; + if (build_huffman_table(priv, bits_ac_luminance, val_ac_luminance, &priv->HTAC[0])) + return -1; - build_huffman_table(bits_dc_chrominance, val_dc_chrominance, &priv->HTDC[1]); - build_huffman_table(bits_ac_chrominance, val_ac_chrominance, &priv->HTAC[1]); + if (build_huffman_table(priv, bits_dc_chrominance, val_dc_chrominance, &priv->HTDC[1])) + return -1; + if (build_huffman_table(priv, bits_ac_chrominance, val_ac_chrominance, &priv->HTAC[1])) + return -1; priv->default_huffman_table_initialized = 1; + return 0; } @@ -1390,6 +1602,44 @@ static void decode_MCU_2x1_3planes(struct jdec_private *priv) IDCT(&priv->component_infos[cCr], priv->Cr, 8); } +static void pixart_decode_MCU_2x1_3planes(struct jdec_private *priv) +{ + unsigned char marker; + + pixart_look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, + 8, marker); + /* I think the marker indicates which quantization table to use, iow + a Pixart JPEG may have a different quantization table per MCU, most + MCU's have 0x44 as marker for which our special Pixart quantization + tables are correct. Unfortunately with a 7302 some blocks also have 0x48, + and sometimes even other values. As 0x48 is quite common too, we really + need to find out the correct table for that, as currently the blocks + with a 0x48 marker look wrong. During normal operation the marker stays + within the range below, if it gets out of this range we're most likely + decoding garbage */ + if (marker < 0x20 || marker > 0x7f) { + snprintf(priv->error_string, sizeof(priv->error_string), + "Pixart JPEG error: invalid MCU marker: 0x%02x\n", + (unsigned int)marker); + longjmp(priv->jump_state, -EIO); + } + skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, 8); + + // Y + pixart_process_Huffman_data_unit(priv, cY); + IDCT(&priv->component_infos[cY], priv->Y, 16); + pixart_process_Huffman_data_unit(priv, cY); + IDCT(&priv->component_infos[cY], priv->Y+8, 16); + + // Cb + pixart_process_Huffman_data_unit(priv, cCb); + IDCT(&priv->component_infos[cCb], priv->Cb, 8); + + // Cr + pixart_process_Huffman_data_unit(priv, cCr); + IDCT(&priv->component_infos[cCr], priv->Cr, 8); +} + /* * Decode a 2x1 * .-------. @@ -1676,9 +1926,9 @@ static int parse_SOS(struct jdec_private *priv, const unsigned char *stream) error("We do not support more than %d DC Huffman table\n", HUFFMAN_TABLES); if (cid != priv->component_infos[i].cid) - error("SOS cid order (%d:%d) isn't compatible with the SOF marker (%d:%d)\n", + error("SOS cid order (%u:%u) isn't compatible with the SOF marker (%u:%u)\n", i, cid, i, priv->component_infos[i].cid); - trace("ComponentId:%d tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4); + trace("ComponentId:%u tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4); #endif priv->component_infos[i].AC_table = &priv->HTAC[table&0xf]; priv->component_infos[i].DC_table = &priv->HTDC[table>>4]; @@ -1723,10 +1973,13 @@ static int parse_DHT(struct jdec_private *priv, const unsigned char *stream) trace("Length of the table: %d\n", count); #endif - if (index & 0xf0 ) - build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]); - else - build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]); + if (index & 0xf0 ) { + if (build_huffman_table(priv, huff_bits, stream, &priv->HTAC[index&0xf])) + return -1; + } else { + if (build_huffman_table(priv, huff_bits, stream, &priv->HTDC[index&0xf])) + return -1; + } length -= 1; length -= 16; @@ -1817,6 +2070,8 @@ static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream) { int chuck_len; int marker; + int sof_marker_found = 0; + int dqt_marker_found = 0; int sos_marker_found = 0; int dht_marker_found = 0; const unsigned char *next_chunck; @@ -1838,10 +2093,12 @@ static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream) case SOF: if (parse_SOF(priv, stream) < 0) return -1; + sof_marker_found = 1; break; case DQT: if (parse_DQT(priv, stream) < 0) return -1; + dqt_marker_found = 1; break; case SOS: if (parse_SOS(priv, stream) < 0) @@ -1865,9 +2122,24 @@ static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream) stream = next_chunck; } + if ( !sof_marker_found || + (!dqt_marker_found && !(priv->flags & TINYJPEG_FLAGS_PIXART_JPEG))) + goto bogus_jpeg_format; + + if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG) { + if (!priv->default_huffman_table_initialized) { + build_quantization_table(priv->Q_tables[0], pixart_quantization[0]); + build_quantization_table(priv->Q_tables[1], pixart_quantization[1]); + } + + /* Pixart JPEG data starts with one unknown / unused byte */ + priv->stream++; + } + if (!dht_marker_found) { trace("No Huffman table loaded, using the default one\n"); - build_default_huffman_tables(priv); + if (build_default_huffman_tables(priv)) + return -1; } #ifdef SANITY_CHECK @@ -1962,6 +2234,13 @@ static const decode_MCU_fct decode_mcu_3comp_table[4] = { decode_MCU_2x2_3planes, }; +static const decode_MCU_fct pixart_decode_mcu_3comp_table[4] = { + NULL, + NULL, + pixart_decode_MCU_2x1_3planes, + NULL, +}; + static const decode_MCU_fct decode_mcu_1comp_table[4] = { decode_MCU_1x1_1plane, decode_MCU_1x2_1plane, @@ -2021,6 +2300,9 @@ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt) bytes_per_blocklines[2] = 0; decode_mcu_table = decode_mcu_3comp_table; + if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG) + decode_mcu_table = pixart_decode_mcu_3comp_table; + switch (pixfmt) { case TINYJPEG_FMT_YUV420P: colorspace_array_conv = convert_colorspace_yuv420p; @@ -2056,6 +2338,8 @@ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt) case TINYJPEG_FMT_GREY: decode_mcu_table = decode_mcu_1comp_table; + if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG) + error("Greyscale output not support for PIXART JPEG's\n"); colorspace_array_conv = convert_colorspace_grey; if (priv->components[0] == NULL) priv->components[0] = (uint8_t *)malloc(priv->width * priv->height); @@ -2064,8 +2348,7 @@ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt) break; default: - trace("Bad pixel format\n"); - return -1; + error("Bad pixel format\n"); } xstride_by_mcu = ystride_by_mcu = 8; @@ -2091,6 +2374,9 @@ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt) trace("Use decode 2x1 sampling\n"); } + if (decode_MCU == NULL) + error("no decode MCU function for this JPEG format (PIXART?)\n"); + resync(priv); /* Don't forget to that block can be either 8 or 16 lines */ @@ -2130,6 +2416,12 @@ int tinyjpeg_decode(struct jdec_private *priv, int pixfmt) } } + if (priv->flags & TINYJPEG_FLAGS_PIXART_JPEG) { + /* Additional sanity check for funky Pixart format */ + if ((priv->stream_end - priv->stream) > 5) + error("Pixart JPEG error, stream does not end with EOF marker\n"); + } + return 0; } diff --git a/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.h b/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.h index 42b60c1ee..b0096f0de 100644 --- a/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.h +++ b/v4l2-apps/lib/libv4l/libv4lconvert/tinyjpeg.h @@ -43,6 +43,7 @@ struct jdec_private; /* Flags that can be set by any applications */ #define TINYJPEG_FLAGS_MJPEG_TABLE (1<<1) +#define TINYJPEG_FLAGS_PIXART_JPEG (1<<2) /* Format accepted in outout */ enum tinyjpeg_fmt { diff --git a/v4l2-apps/test/Makefile b/v4l2-apps/test/Makefile index ae8868c21..faafed14d 100644 --- a/v4l2-apps/test/Makefile +++ b/v4l2-apps/test/Makefile @@ -1,6 +1,6 @@ # Makefile for linuxtv.org v4l2-apps/test -CPPFLAGS += -I../../linux/include +CPPFLAGS += -I../include binaries = ioctl-test \ sliced-vbi-test \ diff --git a/v4l2-apps/test/ioctl-test.c b/v4l2-apps/test/ioctl-test.c index f483338fb..99ad717e5 100644 --- a/v4l2-apps/test/ioctl-test.c +++ b/v4l2-apps/test/ioctl-test.c @@ -42,7 +42,7 @@ typedef __u8 u8; typedef __u32 u32; #include <linux/version.h> -#include "../linux/include/media/v4l2-common.h" +#include <media/v4l2-common.h> #include <linux/video_decoder.h> #else typedef u_int32_t u32; diff --git a/v4l2-apps/util/Makefile b/v4l2-apps/util/Makefile index 41d4712e1..dcef94e0f 100644 --- a/v4l2-apps/util/Makefile +++ b/v4l2-apps/util/Makefile @@ -4,10 +4,10 @@ ifeq ($(KERNEL_DIR),) KERNEL_DIR = /usr endif -CPPFLAGS += -I../../linux/include -D_GNU_SOURCE +CPPFLAGS += -I../include -D_GNU_SOURCE LDFLAGS += -lm -binaries = v4l2-ctl v4l2-dbg ivtv-ctl cx18-ctl v4l-board-dbg +binaries = v4l2-ctl v4l2-dbg v4l2-compliance ivtv-ctl cx18-ctl ifeq ($(prefix),) prefix = /usr @@ -26,12 +26,14 @@ clean:: rm -rf keycodes parse.h keytable qv4l2: - if [ ! -f qv4l2/Makefile ]; then (cd qv4l2; qmake); fi - make -C qv4l2 + -if [ ! -f qv4l2/Makefile ]; then (cd qv4l2; qmake); fi + $(MAKE) -C qv4l2 v4l2-dbg: v4l2-dbg.o v4l2-driverids.o v4l2-chipids.o $(CXX) $^ -o $@ +v4l2-dbg.o: v4l2-dbg.h v4l2-dbg-bttv.h v4l2-dbg-em28xx.h v4l2-dbg-saa7134.h + install: mkdir -p $(prefix)/bin cp $(binaries) $(prefix)/bin @@ -57,14 +59,12 @@ keytables: keytable: keytable.c parse.h keytables -v4l-board-dbg: v4l-board-dbg.c bttv-dbg.h saa7134-dbg.h em28xx-dbg.h - -v4l2-driverids.cpp: ../../linux/include/linux/i2c-id.h +v4l2-driverids.cpp: ../include/linux/i2c-id.h @echo "struct driverid { const char *name; unsigned id; } driverids[] = {" >$@ @grep I2C_DRIVERID_ $^ | sed -e 's/.*I2C_DRIVERID_\([0-9A-Z_]*\)[^0-9]*\([0-9]*\).*/{ "\1", \2 },/' | tr A-Z a-z >>$@ @echo "{ 0, 0 }};" >>$@ -v4l2-chipids.cpp: ../../linux/include/media/v4l2-chip-ident.h +v4l2-chipids.cpp: ../include/media/v4l2-chip-ident.h @echo "struct chipid { const char *name; unsigned id; } chipids[] = {" >$@ @grep V4L2_IDENT_ $^ | sed -e 's/.*V4L2_IDENT_\([0-9A-Z_]*\)[^=]*=[^0-9]*\([0-9]*\).*/{ "\1", \2 },/' | tr A-Z a-z >>$@ @echo "{ 0, 0 }};" >>$@ diff --git a/v4l2-apps/util/ivtv-ctl.c b/v4l2-apps/util/ivtv-ctl.c index ab836e240..af84164e3 100644 --- a/v4l2-apps/util/ivtv-ctl.c +++ b/v4l2-apps/util/ivtv-ctl.c @@ -351,9 +351,9 @@ int main(int argc, char **argv) unsigned short gpio_dir = 0x0; /* GPIO direction bits */ int gpio_set_dir = 0; int passthrough = 0; - int audio_mute = 0; - int stereo_mode = 0; - int bilingual_mode = 0; + long audio_mute = 0; + long stereo_mode = 0; + long bilingual_mode = 0; int debug_level = 0; __u32 reset = 0; int new_debug_level, gdebug_level; @@ -621,7 +621,7 @@ int main(int argc, char **argv) } if (options[OptPassThrough]) { - int source = passthrough ? VIDEO_SOURCE_DEMUX : VIDEO_SOURCE_MEMORY; + long source = passthrough ? VIDEO_SOURCE_DEMUX : VIDEO_SOURCE_MEMORY; doioctl(fd, VIDEO_SELECT_SOURCE, (void *)source, "IVTV_IOC_PASSTHROUGH"); diff --git a/v4l2-apps/util/qv4l2/qv4l2.pro b/v4l2-apps/util/qv4l2/qv4l2.pro index c53a098b5..5e0b7555d 100644 --- a/v4l2-apps/util/qv4l2/qv4l2.pro +++ b/v4l2-apps/util/qv4l2/qv4l2.pro @@ -3,7 +3,7 @@ ###################################################################### TEMPLATE = app -INCLUDEPATH += . ../../../linux/include ../../lib +INCLUDEPATH += . ../../include ../../lib CONFIG += debug # Input diff --git a/v4l2-apps/util/rds/Makefile b/v4l2-apps/util/rds/Makefile index 4f6ebd9f2..fb2213c99 100644 --- a/v4l2-apps/util/rds/Makefile +++ b/v4l2-apps/util/rds/Makefile @@ -1,6 +1,6 @@ # Makefile for linuxtv.org v4l2-apps/util/xc3028-firmware -CPPFLAGS += -I../../../linux/include +CPPFLAGS += -I../../include binaries = rds-saa6588 diff --git a/v4l2-apps/util/v4l-board-dbg.c b/v4l2-apps/util/v4l-board-dbg.c deleted file mode 100644 index e74c7300e..000000000 --- a/v4l2-apps/util/v4l-board-dbg.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - Copyright (C) 2008 Mauro Carvalho Chehab <mchehab@infradead.org> - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include <unistd.h> -#include <stdlib.h> -#include <stdio.h> -#include <string.h> -#include <getopt.h> -#include <fcntl.h> -#include <errno.h> -#include <sys/ioctl.h> -#include <sys/time.h> -#include <linux/types.h> -#include <linux/videodev2.h> - -#include "bttv-dbg.h" -#include "saa7134-dbg.h" -#include "em28xx-dbg.h" - -#define ARRAY_SIZE(arr) ((int)(sizeof(arr) / sizeof((arr)[0]))) - -struct board_list { - char *name; - int prefix; /* Register prefix size */ - struct board_regs *regs; - int regs_size; - struct board_regs *alt_regs; - int alt_regs_size; -}; - -struct board_list boards[] = { - [0] = { /* From bttv-dbg.h */ - .name = BTTV_IDENT, - .prefix = sizeof(BTTV_PREFIX) - 1, - .regs = bt8xx_regs, - .regs_size = ARRAY_SIZE(bt8xx_regs), - .alt_regs = bt8xx_regs_other, - .alt_regs_size = ARRAY_SIZE(bt8xx_regs_other), - }, - [1] = { /* From saa7134-dbg.h */ - .name = SAA7134_IDENT, - .prefix = sizeof(SAA7134_PREFIX) - 1, - .regs = saa7134_regs, - .regs_size = ARRAY_SIZE(saa7134_regs), - .alt_regs = NULL, - .alt_regs_size = 0, - }, - [2] = { /* From em28xx-dbg.h */ - .name = EM28XX_IDENT, - .prefix = sizeof(EM28XX_PREFIX) - 1, - .regs = em28xx_regs, - .regs_size = ARRAY_SIZE(em28xx_regs), - .alt_regs = NULL, - .alt_regs_size = 0, - }, -}; - -static int is_get=0, is_set=0; - -static int doioctl(int fd, int request, void *parm, const char *name) -{ - int retVal; - - printf("ioctl %s ", name); - retVal = ioctl(fd, request, parm); - if (retVal < 0) - printf("failed: %s\n", strerror(errno)); - else - printf("ok\n"); - - return retVal; -} - -static void usage(void) -{ - printf("bttv-dbg <args>\n"); -} - -enum Option { - OptGetReg = 'g', - OptSetReg = 's', - OptHelp = 'h', -}; - -static void print_bin (int val, int size) -{ - int i, j, v; - - printf("("); - for (i = size-1; i >= 0; i--) { - v = (val >> (i * 8)) & 0xff; - for (j = 7; j >= 0; j--) { - int bit = (v >> j) & 0x1; - if (bit) - printf("1"); - else - printf("0"); - } - if (i) - printf(" "); - else - printf(")"); - } -} - -int main(int argc, char **argv) -{ - char *device = strdup("/dev/video0"); - char *reg_set = NULL; - int ch; - int i; - int fd = -1; - struct v4l2_register reg; - struct v4l2_capability cap; - struct board_list *curr_bd; - int board = 0; - struct option long_options[] = { - /* Please keep in alphabetical order of the short option. - That makes it easier to see which options are still free. */ - {"get-reg", no_argument, 0, OptGetReg}, - {"set-reg", required_argument, 0, OptSetReg}, - {"help", no_argument, 0, OptHelp}, - {0, 0, 0, 0} - }; - - /* command args */ - if (argc == 1) { - usage(); - return 0; - } - while (1) { - int option_index = 0; - - ch = getopt_long(argc, argv, "gs:", long_options, &option_index); - if (ch == -1) - break; - - switch (ch) { - case OptHelp: - usage(); - return 0; - case OptGetReg: - is_get++; - break; - case OptSetReg: - is_set++; - reg_set = optarg; - - break; - case '?': - fprintf(stderr, "Unknown argument `%s'\n", - argv[optind]); - usage(); - return 1; - } - } - if (optind < argc) { - printf("unknown arguments: "); - while (optind < argc) - printf("%s ", argv[optind++]); - printf("\n"); - usage(); - return 1; - } - - fd = open(device, O_RDWR); - if (fd < 0) { - fprintf(stderr, "Failed to open %s: %s\n", device, - strerror(errno)); - exit(1); - } - free(device); - - if (ioctl(fd, VIDIOC_QUERYCAP, &cap) < 0) { - printf("Error while reading capabilities\n"); - exit(2); - } - - for (board = ARRAY_SIZE(boards)-1; board >= 0; board--) { - if (!strcasecmp((char *)cap.driver, boards[board].name)) - break; - } - if (board < 0) { - printf("This software doesn't support %s yet\n", cap.driver); - exit(3); - } - - curr_bd = &boards[board]; - - reg.match_type = V4L2_CHIP_MATCH_HOST; - reg.match_chip = 0; - - if (is_get) { - for (i = 0; i < curr_bd->regs_size; i++) { - char name[256]; - reg.reg = curr_bd->regs[i].reg; - if (ioctl(fd, VIDIOC_DBG_G_REGISTER, ®) < 0) { - printf("Error while reading. Maybe you're not root?\n"); - continue; - } - sprintf(name, "%s:", curr_bd->regs[i].name); - - switch (curr_bd->regs[i].size) { - case 1: - printf("%-32s %02llx ", name, reg.val & 0xff); - break; - case 2: - printf("%-32s %04llx ", name, reg.val & 0xffff); - break; - case 4: - printf("%-32s %08llx ", name, reg.val & 0xffffffff); - break; - } - print_bin (reg.val, curr_bd->regs[i].size); - printf("\n"); - } - return 0; - } - - if (is_set) { - char *reg_name; - int val; - int r, size; - unsigned prev; - struct board_regs *bd_reg; - - reg_name = strtok(reg_set, "=:"); - val = strtol(strtok(NULL, "=:"), 0L, 0); - - if (!reg_name) { - printf("set argument is invalid\n"); - return -1; - } - - for (i = curr_bd->regs_size - 1; i >=0 ; i--) { - if (!strcasecmp(reg_name, curr_bd->regs[i].name)) { - bd_reg = &curr_bd->regs[i]; - r = bd_reg->reg; - size = bd_reg->size; - break; - } - } - - if (i < 0) { - for (i = curr_bd->alt_regs_size - 1; i >=0 ; i--) { - if (!strcasecmp(reg_name, curr_bd->alt_regs[i].name)) { - bd_reg = &curr_bd->alt_regs[i]; - r = bd_reg->reg; - size = bd_reg->size; - break; - } - } - } - - if (i < 0) { - for (i = curr_bd->regs_size - 1; i >=0 ; i--) { - if (!strcasecmp(reg_name, curr_bd->regs[i].name + curr_bd->prefix)) { - bd_reg = &curr_bd->regs[i]; - r = bd_reg->reg; - size = bd_reg->size; - break; - } - } - } - - if (i < 0) { - for (i = curr_bd->alt_regs_size - 1; i >=0 ; i--) { - if (!strcasecmp(reg_name, curr_bd->alt_regs[i].name + curr_bd->prefix)) { - bd_reg = &curr_bd->regs[i]; - r = bd_reg->reg; - size = bd_reg->size; - break; - } - } - } - - if (i < 0) { - printf("Register not found\n"); - return -1; - } - - reg.reg = r; - if (ioctl(fd, VIDIOC_DBG_G_REGISTER, ®) < 0) { - printf("Error while reading register 0x%02x\n", r); - return -1; - } - prev = reg.val; - - switch (size) { - case 1: - reg.val = (reg.val & (~0xff)) | val; - break; - case 2: - reg.val = (reg.val & (~0xffff)) | val; - break; - case 4: - reg.val = val; - break; - } - - printf("Changing value of register %s(0x%x) from 0x%02x to 0x%02x\n", - bd_reg->name, r, prev, (unsigned int)reg.val); - - prev = reg.val; - - if (ioctl(fd, VIDIOC_DBG_S_REGISTER, ®) < 0) { - printf("Error while writing\n"); - return -1; - } - if (ioctl(fd, VIDIOC_DBG_G_REGISTER, ®) < 0) { - printf("Error while reading register 0x%02x\n", r); - return -1; - } - if (reg.val != prev) { - printf("Value of register %s(0x%x) is now 0x%02x\n", - bd_reg->name, r, (unsigned int)reg.val); - } - } - - close(fd); - exit(0); -} diff --git a/v4l2-apps/util/v4l2-compliance.cpp b/v4l2-apps/util/v4l2-compliance.cpp new file mode 100644 index 000000000..2fe5292fe --- /dev/null +++ b/v4l2-apps/util/v4l2-compliance.cpp @@ -0,0 +1,1122 @@ +/* + V4L2 API compliance test tool. + + 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 as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <unistd.h> +#include <features.h> /* Uses _GNU_SOURCE to define getsubopt in stdlib.h */ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <ctype.h> +#include <errno.h> +#include <sys/ioctl.h> +#include <sys/time.h> +#include <math.h> +#include <sys/klog.h> + +#include <linux/videodev2.h> + +#include <list> +#include <vector> +#include <map> +#include <string> + +/* Short option list + + Please keep in alphabetical order. + That makes it easier to see which short options are still free. + + In general the lower case is used to set something and the upper + case is used to retrieve a setting. */ +enum Option { + OptSetDevice = 'd', + OptGetDriverInfo = 'D', + OptHelp = 'h', + OptTest = 't', + OptVerbose = 'v', + OptLast = 256 +}; + +enum Test { + TestCap = 0, + TestChipIdent, + TestRegister, + TestLogStatus, + TestMax +}; + +static int test[TestMax]; + +static char options[OptLast]; + +static int app_result; +static int verbose; + +static unsigned caps; + +typedef std::vector<struct v4l2_ext_control> ctrl_list; +static ctrl_list user_ctrls; +static ctrl_list mpeg_ctrls; + +typedef std::map<std::string, unsigned> ctrl_strmap; +static ctrl_strmap ctrl_str2id; +typedef std::map<unsigned, std::string> ctrl_idmap; +static ctrl_idmap ctrl_id2str; + +typedef std::list<std::string> ctrl_get_list; +static ctrl_get_list get_ctrls; + +typedef std::map<std::string,std::string> ctrl_set_map; +static ctrl_set_map set_ctrls; + +typedef struct { + unsigned flag; + const char *str; +} flag_def; + +static const flag_def service_def[] = { + { V4L2_SLICED_TELETEXT_B, "teletext" }, + { V4L2_SLICED_VPS, "vps" }, + { V4L2_SLICED_CAPTION_525, "cc" }, + { V4L2_SLICED_WSS_625, "wss" }, + { 0, NULL } +}; + +/* fmts specified */ +#define FmtWidth (1L<<0) +#define FmtHeight (1L<<1) +#define FmtChromaKey (1L<<2) +#define FmtGlobalAlpha (1L<<3) + +/* crop specified */ +#define CropWidth (1L<<0) +#define CropHeight (1L<<1) +#define CropLeft (1L<<2) +#define CropTop (1L<<3) + +static struct option long_options[] = { + {"device", required_argument, 0, OptSetDevice}, + {"help", no_argument, 0, OptHelp}, + {"info", no_argument, 0, OptGetDriverInfo}, + {"verbose", no_argument, 0, OptVerbose}, + {"test", required_argument, 0, OptTest}, + {0, 0, 0, 0} +}; + +static void usage(void) +{ + printf("Usage:\n"); + printf("Common options:\n"); + printf(" -D, --info show driver info [VIDIOC_QUERYCAP]\n"); + printf(" -d, --device=<dev> use device <dev> instead of /dev/video0\n"); + printf(" if <dev> is a single digit, then /dev/video<dev> is used\n"); + printf(" -h, --help display this help message\n"); + printf(" -t, --test=<num> run specified test.\n"); + printf(" By default all tests are run.\n"); + printf(" 0 = test VIDIOC_QUERYCAP\n"); + printf(" -v, --verbose turn on verbose ioctl error reporting.\n"); + exit(0); +} + +static std::string num2s(unsigned num) +{ + char buf[10]; + + sprintf(buf, "%08x", num); + return buf; +} + +static std::string buftype2s(int type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return "Video Capture"; + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return "Video Output"; + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + return "Video Overlay"; + case V4L2_BUF_TYPE_VBI_CAPTURE: + return "VBI Capture"; + case V4L2_BUF_TYPE_VBI_OUTPUT: + return "VBI Output"; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + return "Sliced VBI Capture"; + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + return "Sliced VBI Output"; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + return "Video Output Overlay"; + case V4L2_BUF_TYPE_PRIVATE: + return "Private"; + default: + return "Unknown (" + num2s(type) + ")"; + } +} + +static std::string fcc2s(unsigned int val) +{ + std::string s; + + s += val & 0xff; + s += (val >> 8) & 0xff; + s += (val >> 16) & 0xff; + s += (val >> 24) & 0xff; + return s; +} + +static std::string field2s(int val) +{ + switch (val) { + case V4L2_FIELD_ANY: + return "Any"; + case V4L2_FIELD_NONE: + return "None"; + case V4L2_FIELD_TOP: + return "Top"; + case V4L2_FIELD_BOTTOM: + return "Bottom"; + case V4L2_FIELD_INTERLACED: + return "Interlaced"; + case V4L2_FIELD_SEQ_TB: + return "Sequential Top-Bottom"; + case V4L2_FIELD_SEQ_BT: + return "Sequential Bottom-Top"; + case V4L2_FIELD_ALTERNATE: + return "Alternating"; + case V4L2_FIELD_INTERLACED_TB: + return "Interlaced Top-Bottom"; + case V4L2_FIELD_INTERLACED_BT: + return "Interlaced Bottom-Top"; + default: + return "Unknown (" + num2s(val) + ")"; + } +} + +static std::string colorspace2s(int val) +{ + switch (val) { + case V4L2_COLORSPACE_SMPTE170M: + return "Broadcast NTSC/PAL (SMPTE170M/ITU601)"; + case V4L2_COLORSPACE_SMPTE240M: + return "1125-Line (US) HDTV (SMPTE240M)"; + case V4L2_COLORSPACE_REC709: + return "HDTV and modern devices (ITU709)"; + case V4L2_COLORSPACE_BT878: + return "Broken Bt878"; + case V4L2_COLORSPACE_470_SYSTEM_M: + return "NTSC/M (ITU470/ITU601)"; + case V4L2_COLORSPACE_470_SYSTEM_BG: + return "PAL/SECAM BG (ITU470/ITU601)"; + case V4L2_COLORSPACE_JPEG: + return "JPEG (JFIF/ITU601)"; + case V4L2_COLORSPACE_SRGB: + return "SRGB"; + default: + return "Unknown (" + num2s(val) + ")"; + } +} + +static std::string flags2s(unsigned val, const flag_def *def) +{ + std::string s; + + while (def->flag) { + if (val & def->flag) { + if (s.length()) s += " "; + s += def->str; + } + def++; + } + return s; +} + +static void print_sliced_vbi_cap(struct v4l2_sliced_vbi_cap &cap) +{ + printf("\tType : %s\n", buftype2s(cap.type).c_str()); + printf("\tService Set : %s\n", + flags2s(cap.service_set, service_def).c_str()); + for (int i = 0; i < 24; i++) { + printf("\tService Line %2d: %8s / %-8s\n", i, + flags2s(cap.service_lines[0][i], service_def).c_str(), + flags2s(cap.service_lines[1][i], service_def).c_str()); + } +} + +static std::string name2var(unsigned char *name) +{ + std::string s; + + while (*name) { + if (*name == ' ') s += "_"; + else s += std::string(1, tolower(*name)); + name++; + } + return s; +} + +static void print_qctrl(int fd, struct v4l2_queryctrl *queryctrl, + struct v4l2_ext_control *ctrl, int show_menus) +{ + struct v4l2_querymenu qmenu = { 0 }; + std::string s = name2var(queryctrl->name); + int i; + + qmenu.id = queryctrl->id; + switch (queryctrl->type) { + case V4L2_CTRL_TYPE_INTEGER: + printf("%31s (int) : min=%d max=%d step=%d default=%d value=%d", + s.c_str(), + queryctrl->minimum, queryctrl->maximum, + queryctrl->step, queryctrl->default_value, + ctrl->value); + break; + case V4L2_CTRL_TYPE_INTEGER64: + printf("%31s (int64): value=%lld", s.c_str(), ctrl->value64); + break; + case V4L2_CTRL_TYPE_BOOLEAN: + printf("%31s (bool) : default=%d value=%d", + s.c_str(), + queryctrl->default_value, ctrl->value); + break; + case V4L2_CTRL_TYPE_MENU: + printf("%31s (menu) : min=%d max=%d default=%d value=%d", + s.c_str(), + queryctrl->minimum, queryctrl->maximum, + queryctrl->default_value, ctrl->value); + break; + case V4L2_CTRL_TYPE_BUTTON: + printf("%31s (button)\n", s.c_str()); + break; + default: break; + } + if (queryctrl->flags) { + const flag_def def[] = { + { V4L2_CTRL_FLAG_GRABBED, "grabbed" }, + { V4L2_CTRL_FLAG_READ_ONLY, "readonly" }, + { V4L2_CTRL_FLAG_UPDATE, "update" }, + { V4L2_CTRL_FLAG_INACTIVE, "inactive" }, + { V4L2_CTRL_FLAG_SLIDER, "slider" }, + { 0, NULL } + }; + printf(" flags=%s", flags2s(queryctrl->flags, def).c_str()); + } + printf("\n"); + if (queryctrl->type == V4L2_CTRL_TYPE_MENU && show_menus) { + for (i = 0; i <= queryctrl->maximum; i++) { + qmenu.index = i; + if (ioctl(fd, VIDIOC_QUERYMENU, &qmenu)) + continue; + printf("\t\t\t\t%d: %s\n", i, qmenu.name); + } + } +} + +static int print_control(int fd, struct v4l2_queryctrl &qctrl, int show_menus) +{ + struct v4l2_control ctrl = { 0 }; + struct v4l2_ext_control ext_ctrl = { 0 }; + struct v4l2_ext_controls ctrls = { 0 }; + + if (qctrl.flags & V4L2_CTRL_FLAG_DISABLED) + return 1; + if (qctrl.type == V4L2_CTRL_TYPE_CTRL_CLASS) { + printf("\n%s\n\n", qctrl.name); + return 1; + } + ext_ctrl.id = qctrl.id; + ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(qctrl.id); + ctrls.count = 1; + ctrls.controls = &ext_ctrl; + if (V4L2_CTRL_ID2CLASS(qctrl.id) != V4L2_CTRL_CLASS_USER && + qctrl.id < V4L2_CID_PRIVATE_BASE) { + if (ioctl(fd, VIDIOC_G_EXT_CTRLS, &ctrls)) { + printf("error %d getting ext_ctrl %s\n", + errno, qctrl.name); + return 0; + } + } + else { + ctrl.id = qctrl.id; + if (ioctl(fd, VIDIOC_G_CTRL, &ctrl)) { + printf("error %d getting ctrl %s\n", + errno, qctrl.name); + return 0; + } + ext_ctrl.value = ctrl.value; + } + print_qctrl(fd, &qctrl, &ext_ctrl, show_menus); + return 1; +} + +static void list_controls(int fd, int show_menus) +{ + struct v4l2_queryctrl qctrl = { V4L2_CTRL_FLAG_NEXT_CTRL }; + int id; + + while (ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) { + print_control(fd, qctrl, show_menus); + qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; + } + if (qctrl.id != V4L2_CTRL_FLAG_NEXT_CTRL) + return; + for (id = V4L2_CID_USER_BASE; id < V4L2_CID_LASTP1; id++) { + qctrl.id = id; + if (ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) + print_control(fd, qctrl, show_menus); + } + for (qctrl.id = V4L2_CID_PRIVATE_BASE; + ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0; qctrl.id++) { + print_control(fd, qctrl, show_menus); + } +} + +static void find_controls(int fd) +{ + struct v4l2_queryctrl qctrl = { V4L2_CTRL_FLAG_NEXT_CTRL }; + int id; + + while (ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0) { + if (qctrl.type != V4L2_CTRL_TYPE_CTRL_CLASS && + !(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { + ctrl_str2id[name2var(qctrl.name)] = qctrl.id; + ctrl_id2str[qctrl.id] = name2var(qctrl.name); + } + qctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; + } + if (qctrl.id != V4L2_CTRL_FLAG_NEXT_CTRL) + return; + for (id = V4L2_CID_USER_BASE; id < V4L2_CID_LASTP1; id++) { + qctrl.id = id; + if (ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0 && + !(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) + ctrl_str2id[name2var(qctrl.name)] = qctrl.id; + } + for (qctrl.id = V4L2_CID_PRIVATE_BASE; + ioctl(fd, VIDIOC_QUERYCTRL, &qctrl) == 0; qctrl.id++) { + if (!(qctrl.flags & V4L2_CTRL_FLAG_DISABLED)) + ctrl_str2id[name2var(qctrl.name)] = qctrl.id; + } +} + +static std::string fbufcap2s(unsigned cap) +{ + std::string s; + + if (cap & V4L2_FBUF_CAP_EXTERNOVERLAY) + s += "\t\t\tExtern Overlay\n"; + if (cap & V4L2_FBUF_CAP_CHROMAKEY) + s += "\t\t\tChromakey\n"; + if (cap & V4L2_FBUF_CAP_GLOBAL_ALPHA) + s += "\t\t\tGlobal Alpha\n"; + if (cap & V4L2_FBUF_CAP_LOCAL_ALPHA) + s += "\t\t\tLocal Alpha\n"; + if (cap & V4L2_FBUF_CAP_LOCAL_INV_ALPHA) + s += "\t\t\tLocal Inverted Alpha\n"; + if (cap & V4L2_FBUF_CAP_LIST_CLIPPING) + s += "\t\t\tClipping List\n"; + if (cap & V4L2_FBUF_CAP_BITMAP_CLIPPING) + s += "\t\t\tClipping Bitmap\n"; + if (s.empty()) s += "\t\t\t\n"; + return s; +} + +static std::string fbufflags2s(unsigned fl) +{ + std::string s; + + if (fl & V4L2_FBUF_FLAG_PRIMARY) + s += "\t\t\tPrimary Graphics Surface\n"; + if (fl & V4L2_FBUF_FLAG_OVERLAY) + s += "\t\t\tOverlay Matches Capture/Output Size\n"; + if (fl & V4L2_FBUF_FLAG_CHROMAKEY) + s += "\t\t\tChromakey\n"; + if (fl & V4L2_FBUF_FLAG_GLOBAL_ALPHA) + s += "\t\t\tGlobal Alpha\n"; + if (fl & V4L2_FBUF_FLAG_LOCAL_ALPHA) + s += "\t\t\tLocal Alpha\n"; + if (fl & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA) + s += "\t\t\tLocal Inverted Alpha\n"; + if (s.empty()) s += "\t\t\t\n"; + return s; +} + +static void printfbuf(const struct v4l2_framebuffer &fb) +{ + int is_ext = fb.capability & V4L2_FBUF_CAP_EXTERNOVERLAY; + + printf("Framebuffer Format:\n"); + printf("\tCapability : %s", fbufcap2s(fb.capability).c_str() + 3); + printf("\tFlags : %s", fbufflags2s(fb.flags).c_str() + 3); + if (fb.base) + printf("\tBase : 0x%p\n", fb.base); + printf("\tWidth : %d\n", fb.fmt.width); + printf("\tHeight : %d\n", fb.fmt.height); + printf("\tPixel Format : %s\n", fcc2s(fb.fmt.pixelformat).c_str()); + if (!is_ext) { + printf("\tBytes per Line: %d\n", fb.fmt.bytesperline); + printf("\tSize image : %d\n", fb.fmt.sizeimage); + printf("\tColorspace : %s\n", colorspace2s(fb.fmt.colorspace).c_str()); + if (fb.fmt.priv) + printf("\tCustom Info : %08x\n", fb.fmt.priv); + } +} + +static void printcrop(const struct v4l2_crop &crop) +{ + printf("Crop: Left %d, Top %d, Width %d, Height %d\n", + crop.c.left, crop.c.top, crop.c.width, crop.c.height); +} + +static void printcropcap(const struct v4l2_cropcap &cropcap) +{ + printf("Crop Capability %s:\n", buftype2s(cropcap.type).c_str()); + printf("\tBounds : Left %d, Top %d, Width %d, Height %d\n", + cropcap.bounds.left, cropcap.bounds.top, cropcap.bounds.width, cropcap.bounds.height); + printf("\tDefault : Left %d, Top %d, Width %d, Height %d\n", + cropcap.defrect.left, cropcap.defrect.top, cropcap.defrect.width, cropcap.defrect.height); + printf("\tPixel Aspect: %u/%u\n", cropcap.pixelaspect.numerator, cropcap.pixelaspect.denominator); +} + +static void printfmt(struct v4l2_format vfmt) +{ + const flag_def vbi_def[] = { + { V4L2_VBI_UNSYNC, "unsynchronized" }, + { V4L2_VBI_INTERLACED, "interlaced" }, + { 0, NULL } + }; + printf("Format %s:\n", buftype2s(vfmt.type).c_str()); + + switch (vfmt.type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + printf("\tWidth/Height : %u/%u\n", vfmt.fmt.pix.width, vfmt.fmt.pix.height); + printf("\tPixel Format : %s\n", fcc2s(vfmt.fmt.pix.pixelformat).c_str()); + printf("\tField : %s\n", field2s(vfmt.fmt.pix.field).c_str()); + printf("\tBytes per Line: %u\n", vfmt.fmt.pix.bytesperline); + printf("\tSize Image : %u\n", vfmt.fmt.pix.sizeimage); + printf("\tColorspace : %s\n", colorspace2s(vfmt.fmt.pix.colorspace).c_str()); + if (vfmt.fmt.pix.priv) + printf("\tCustom Info : %08x\n", vfmt.fmt.pix.priv); + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: + case V4L2_BUF_TYPE_VIDEO_OVERLAY: + printf("\tLeft/Top : %d/%d\n", + vfmt.fmt.win.w.left, vfmt.fmt.win.w.top); + printf("\tWidth/Height: %d/%d\n", + vfmt.fmt.win.w.width, vfmt.fmt.win.w.height); + printf("\tField : %s\n", field2s(vfmt.fmt.win.field).c_str()); + printf("\tChroma Key : 0x%08x\n", vfmt.fmt.win.chromakey); + printf("\tGlobal Alpha: 0x%02x\n", vfmt.fmt.win.global_alpha); + printf("\tClip Count : %u\n", vfmt.fmt.win.clipcount); + printf("\tClip Bitmap : %s\n", vfmt.fmt.win.bitmap ? "Yes" : "No"); + break; + case V4L2_BUF_TYPE_VBI_CAPTURE: + case V4L2_BUF_TYPE_VBI_OUTPUT: + printf("\tSampling Rate : %u Hz\n", vfmt.fmt.vbi.sampling_rate); + printf("\tOffset : %u samples (%g secs after leading edge)\n", + vfmt.fmt.vbi.offset, + (double)vfmt.fmt.vbi.offset / (double)vfmt.fmt.vbi.sampling_rate); + printf("\tSamples per Line: %u\n", vfmt.fmt.vbi.samples_per_line); + printf("\tSample Format : %s\n", fcc2s(vfmt.fmt.vbi.sample_format).c_str()); + printf("\tStart 1st Field : %u\n", vfmt.fmt.vbi.start[0]); + printf("\tCount 1st Field : %u\n", vfmt.fmt.vbi.count[0]); + printf("\tStart 2nd Field : %u\n", vfmt.fmt.vbi.start[1]); + printf("\tCount 2nd Field : %u\n", vfmt.fmt.vbi.count[1]); + if (vfmt.fmt.vbi.flags) + printf("\tFlags : %s\n", flags2s(vfmt.fmt.vbi.flags, vbi_def).c_str()); + break; + case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE: + case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT: + printf("\tService Set : %s\n", + flags2s(vfmt.fmt.sliced.service_set, service_def).c_str()); + for (int i = 0; i < 24; i++) { + printf("\tService Line %2d: %8s / %-8s\n", i, + flags2s(vfmt.fmt.sliced.service_lines[0][i], service_def).c_str(), + flags2s(vfmt.fmt.sliced.service_lines[1][i], service_def).c_str()); + } + printf("\tI/O Size : %u\n", vfmt.fmt.sliced.io_size); + break; + case V4L2_BUF_TYPE_PRIVATE: + break; + } +} + +static void print_video_formats(int fd, enum v4l2_buf_type type) +{ + struct v4l2_fmtdesc fmt; + + fmt.index = 0; + fmt.type = type; + while (ioctl(fd, VIDIOC_ENUM_FMT, &fmt) >= 0) { + printf("\tType : %s\n", buftype2s(type).c_str()); + printf("\tPixelformat : %s", fcc2s(fmt.pixelformat).c_str()); + if (fmt.flags) + printf(" (compressed)"); + printf("\n"); + printf("\tName : %s\n", fmt.description); + printf("\n"); + fmt.index++; + } +} + +static char *pts_to_string(char *str, unsigned long pts) +{ + static char buf[256]; + int hours, minutes, seconds, fracsec; + float fps; + int frame; + char *p = (str) ? str : buf; + + static const int MPEG_CLOCK_FREQ = 90000; + seconds = pts / MPEG_CLOCK_FREQ; + fracsec = pts % MPEG_CLOCK_FREQ; + + minutes = seconds / 60; + seconds = seconds % 60; + + hours = minutes / 60; + minutes = minutes % 60; + + fps = 30; + frame = (int)ceilf(((float)fracsec / (float)MPEG_CLOCK_FREQ) * fps); + + snprintf(p, sizeof(buf), "%d:%02d:%02d:%d", hours, minutes, seconds, + frame); + return p; +} + +static const char *audmode2s(int audmode) +{ + switch (audmode) { + case V4L2_TUNER_MODE_STEREO: return "stereo"; + case V4L2_TUNER_MODE_LANG1: return "lang1"; + case V4L2_TUNER_MODE_LANG2: return "lang2"; + case V4L2_TUNER_MODE_LANG1_LANG2: return "bilingual"; + case V4L2_TUNER_MODE_MONO: return "mono"; + default: return "unknown"; + } +} + +static std::string rxsubchans2s(int rxsubchans) +{ + std::string s; + + if (rxsubchans & V4L2_TUNER_SUB_MONO) + s += "mono "; + if (rxsubchans & V4L2_TUNER_SUB_STEREO) + s += "stereo "; + if (rxsubchans & V4L2_TUNER_SUB_LANG1) + s += "lang1 "; + if (rxsubchans & V4L2_TUNER_SUB_LANG2) + s += "lang2 "; + return s; +} + +static std::string tcap2s(unsigned cap) +{ + std::string s; + + if (cap & V4L2_TUNER_CAP_LOW) + s += "62.5 Hz "; + else + s += "62.5 kHz "; + if (cap & V4L2_TUNER_CAP_NORM) + s += "multi-standard "; + if (cap & V4L2_TUNER_CAP_STEREO) + s += "stereo "; + if (cap & V4L2_TUNER_CAP_LANG1) + s += "lang1 "; + if (cap & V4L2_TUNER_CAP_LANG2) + s += "lang2 "; + return s; +} + +static std::string cap2s(unsigned cap) +{ + std::string s; + + if (cap & V4L2_CAP_VIDEO_CAPTURE) + s += "\t\tVideo Capture\n"; + if (cap & V4L2_CAP_VIDEO_OUTPUT) + s += "\t\tVideo Output\n"; + if (cap & V4L2_CAP_VIDEO_OVERLAY) + s += "\t\tVideo Overlay\n"; + if (cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY) + s += "\t\tVideo Output Overlay\n"; + if (cap & V4L2_CAP_VBI_CAPTURE) + s += "\t\tVBI Capture\n"; + if (cap & V4L2_CAP_VBI_OUTPUT) + s += "\t\tVBI Output\n"; + if (cap & V4L2_CAP_SLICED_VBI_CAPTURE) + s += "\t\tSliced VBI Capture\n"; + if (cap & V4L2_CAP_SLICED_VBI_OUTPUT) + s += "\t\tSliced VBI Output\n"; + if (cap & V4L2_CAP_RDS_CAPTURE) + s += "\t\tRDS Capture\n"; + if (cap & V4L2_CAP_TUNER) + s += "\t\tTuner\n"; + if (cap & V4L2_CAP_AUDIO) + s += "\t\tAudio\n"; + if (cap & V4L2_CAP_RADIO) + s += "\t\tRadio\n"; + if (cap & V4L2_CAP_READWRITE) + s += "\t\tRead/Write\n"; + if (cap & V4L2_CAP_ASYNCIO) + s += "\t\tAsync I/O\n"; + if (cap & V4L2_CAP_STREAMING) + s += "\t\tStreaming\n"; + return s; +} + +static v4l2_std_id parse_pal(const char *pal) +{ + if (pal[0] == '-') { + switch (pal[1]) { + case '6': + return V4L2_STD_PAL_60; + case 'b': + case 'B': + case 'g': + case 'G': + return V4L2_STD_PAL_BG; + case 'h': + case 'H': + return V4L2_STD_PAL_H; + case 'n': + case 'N': + if (pal[2] == 'c' || pal[2] == 'C') + return V4L2_STD_PAL_Nc; + return V4L2_STD_PAL_N; + case 'i': + case 'I': + return V4L2_STD_PAL_I; + case 'd': + case 'D': + case 'k': + case 'K': + return V4L2_STD_PAL_DK; + case 'M': + case 'm': + return V4L2_STD_PAL_M; + case '-': + break; + } + } + fprintf(stderr, "pal specifier not recognised\n"); + return 0; +} + +static v4l2_std_id parse_secam(const char *secam) +{ + if (secam[0] == '-') { + switch (secam[1]) { + case 'b': + case 'B': + case 'g': + case 'G': + case 'h': + case 'H': + return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H; + case 'd': + case 'D': + case 'k': + case 'K': + return V4L2_STD_SECAM_DK; + case 'l': + case 'L': + if (secam[2] == 'C' || secam[2] == 'c') + return V4L2_STD_SECAM_LC; + return V4L2_STD_SECAM_L; + case '-': + break; + } + } + fprintf(stderr, "secam specifier not recognised\n"); + return 0; +} + +static v4l2_std_id parse_ntsc(const char *ntsc) +{ + if (ntsc[0] == '-') { + switch (ntsc[1]) { + case 'm': + case 'M': + return V4L2_STD_NTSC_M; + case 'j': + case 'J': + return V4L2_STD_NTSC_M_JP; + case 'k': + case 'K': + return V4L2_STD_NTSC_M_KR; + case '-': + break; + } + } + fprintf(stderr, "ntsc specifier not recognised\n"); + return 0; +} + +static int doioctl(int fd, int request, void *parm, const char *name) +{ + int retVal; + int e; + + errno = 0; + retVal = ioctl(fd, request, parm); + e = errno; + if (verbose) + printf("\t\t%s returned %d (%s)\n", name, retVal, strerror(e)); + if (retVal == 0) return retVal; + if (retVal != -1) { + return -1; + } + retVal = e; + return retVal; +} + +static int parse_subopt(char **subs, char * const *subopts, char **value) +{ + int opt = getsubopt(subs, subopts, value); + + if (opt == -1) { + fprintf(stderr, "Invalid suboptions specified\n"); + usage(); + exit(1); + } + if (value == NULL) { + fprintf(stderr, "No value given to suboption <%s>\n", + subopts[opt]); + usage(); + exit(1); + } + return opt; +} + +static void parse_next_subopt(char **subs, char **value) +{ + static char *const subopts[] = { + NULL + }; + int opt = getsubopt(subs, subopts, value); + + if (value == NULL) { + fprintf(stderr, "No value given to suboption <%s>\n", + subopts[opt]); + usage(); + exit(1); + } +} + +static void print_std(const char *prefix, const char *stds[], unsigned long long std) +{ + int first = 1; + + printf("\t%s-", prefix); + while (*stds) { + if (std & 1) { + if (!first) + printf("/"); + first = 0; + printf("%s", *stds); + } + stds++; + std >>= 1; + } + printf("\n"); +} + +static const char *ok(int res) +{ + if (res) + app_result = res; + return res ? "FAIL" : "OK"; +} + +static int check_string(const char *s, int len, const char *fld) +{ + if (strlen(s) == 0) { + if (verbose) + printf("%s field empty\n", fld); + return -1; + } + if (strlen(s) >= len) { + if (verbose) + printf("%s field not 0-terminated\n", fld); + return -1; + } + return 0; +} + +static int check_ustring(const __u8 *s, int len, const char *fld) +{ + return check_string((const char *)s, len, fld); +} + +static int check_0(void *p, int len) +{ + __u8 *q = (__u8 *)p; + + while (len--) + if (*q++) { + if (verbose) + printf("array not zeroed by driver\n"); + return -1; + } + return 0; +} + +static int testCap(int fd) +{ + struct v4l2_capability vcap; + __u32 caps; + + if (doioctl(fd, VIDIOC_QUERYCAP, &vcap, "VIDIOC_QUERYCAP")) + return -1; + if (check_ustring(vcap.driver, sizeof(vcap.driver), "driver")) + return -1; + if (check_ustring(vcap.card, sizeof(vcap.card), "card")) + return -1; + if (check_ustring(vcap.bus_info, sizeof(vcap.bus_info), "bus_info")) + return -1; + if (check_0(vcap.reserved, sizeof(vcap.reserved))) + return -1; + caps = vcap.capabilities; + if (caps == 0) { + if (verbose) printf("no capabilities set\n"); + return -1; + } + return 0; +} + +static int testChipIdent(int fd) +{ + struct v4l2_chip_ident chip; + int ret; + + chip.match_type = V4L2_CHIP_MATCH_HOST; + chip.match_chip = 0; + ret = doioctl(fd, VIDIOC_G_CHIP_IDENT, &chip, "VIDIOC_G_CHIP_IDENT"); + // Must return either 0 (OK) or EINVAL (not supported) + if (ret == 0) { + struct v4l2_chip_ident orig; + + // set invalid match_type + chip.match_type = V4L2_CHIP_MATCH_I2C_ADDR + 1; + chip.match_chip = 0xdeadbeef; + chip.ident = 0xdeadbeef; + chip.revision = 0xdeadbeef; + orig = chip; + ret = doioctl(fd, VIDIOC_G_CHIP_IDENT, &chip, "VIDIOC_G_CHIP_IDENT"); + if (ret != EINVAL) { + if (verbose) + printf("Invalid match_type accepted\n"); + return -1; + } + if (memcmp(&orig, &chip, sizeof(chip))) { + if (verbose) + printf("Error, but struct modified\n"); + return -1; + } + return 0; + } + return ret != EINVAL; +} + +static int testRegister(int fd) +{ + struct v4l2_register reg; + struct v4l2_chip_ident chip; + int ret; + int uid = getuid(); + + reg.match_type = V4L2_CHIP_MATCH_HOST; + reg.match_chip = 0; + reg.reg = 0; + ret = doioctl(fd, VIDIOC_DBG_G_REGISTER, ®, "VIDIOC_DBG_G_REGISTER"); + if (ret == EINVAL) + return 0; + if (uid && ret != EPERM) { + printf("Not allowed to call VIDIOC_DBG_G_REGISTER unless root\n"); + return -1; + } + if (uid == 0 && ret) { + printf("Not allowed to call VIDIOC_DBG_G_REGISTER even though we are root\n"); + return -1; + } + chip.match_type = V4L2_CHIP_MATCH_HOST; + chip.match_chip = 0; + if (doioctl(fd, VIDIOC_G_CHIP_IDENT, &chip, "VIDIOC_G_CHIP_IDENT")) { + printf("Must support VIDIOC_G_CHIP_IDENT\n"); + return -1; + } + if (uid) { + // Don't test S_REGISTER as root, don't want to risk + // messing with registers in the compliance test. + reg.reg = reg.val = 0; + ret = doioctl(fd, VIDIOC_DBG_S_REGISTER, ®, "VIDIOC_DBG_S_REGISTER"); + if (ret != EINVAL && ret != EPERM) { + printf("Invalid error calling VIDIOC_DBG_S_REGISTER as non-root\n"); + return -1; + } + } + return 0; +} + +static int testLogStatus(int fd) +{ + int ret = doioctl(fd, VIDIOC_LOG_STATUS, NULL, "VIDIOC_LOG_STATUS"); + + return (ret == 0 || ret == EINVAL) ? 0 : -1; +} + +int main(int argc, char **argv) +{ + char *value, *subs; + int i; + unsigned t; + int fd = -1; + + /* command args */ + int ch; + const char *device = "/dev/video0"; /* -d device */ + struct v4l2_capability vcap; /* list_cap */ + char short_options[26 * 2 * 2 + 1]; + int idx = 0; + int tests = 0; + + for (i = 0; long_options[i].name; i++) { + if (!isalpha(long_options[i].val)) + continue; + short_options[idx++] = long_options[i].val; + if (long_options[i].has_arg == required_argument) + short_options[idx++] = ':'; + } + while (1) { + int option_index = 0; + + short_options[idx] = 0; + ch = getopt_long(argc, argv, short_options, + long_options, &option_index); + if (ch == -1) + break; + + options[(int)ch] = 1; + switch (ch) { + case OptHelp: + usage(); + return 0; + case OptTest: + t = strtoul(optarg, NULL, 0); + + if (t >= TestMax) + usage(); + test[t] = 1; + tests++; + break; + case OptSetDevice: + device = optarg; + if (device[0] >= '0' && device[0] <= '9' && device[1] == 0) { + static char newdev[20]; + char dev = device[0]; + + sprintf(newdev, "/dev/video%c", dev); + device = newdev; + } + break; + case ':': + fprintf(stderr, "Option `%s' requires a value\n", + argv[optind]); + usage(); + return 1; + case '?': + fprintf(stderr, "Unknown argument `%s'\n", + argv[optind]); + usage(); + return 1; + } + } + if (optind < argc) { + printf("unknown arguments: "); + while (optind < argc) + printf("%s ", argv[optind++]); + printf("\n"); + usage(); + return 1; + } + verbose = options[OptVerbose]; + if (!tests) { + for (t = 0; t < TestMax; t++) + test[t] = 1; + } + + if ((fd = open(device, O_RDWR)) < 0) { + fprintf(stderr, "Failed to open %s: %s\n", device, + strerror(errno)); + exit(1); + } + + ioctl(fd, VIDIOC_QUERYCAP, &vcap, "VIDIOC_QUERYCAP"); + caps = vcap.capabilities; + find_controls(fd); + for (ctrl_get_list::iterator iter = get_ctrls.begin(); iter != get_ctrls.end(); ++iter) { + if (ctrl_str2id.find(*iter) == ctrl_str2id.end()) { + fprintf(stderr, "unknown control '%s'\n", (*iter).c_str()); + exit(1); + } + } + for (ctrl_set_map::iterator iter = set_ctrls.begin(); iter != set_ctrls.end(); ++iter) { + if (ctrl_str2id.find(iter->first) == ctrl_str2id.end()) { + fprintf(stderr, "unknown control '%s'\n", iter->first.c_str()); + exit(1); + } + } + + /* Information Opts */ + + if (options[OptGetDriverInfo]) { + printf("Driver Info:\n"); + printf("\tDriver name : %s\n", vcap.driver); + printf("\tCard type : %s\n", vcap.card); + printf("\tBus info : %s\n", vcap.bus_info); + printf("\tDriver version: %d\n", vcap.version); + printf("\tCapabilities : 0x%08X\n", vcap.capabilities); + printf("%s", cap2s(vcap.capabilities).c_str()); + } + + printf("Compliance test for device %s:\n\n", device); + + printf("Required ioctls:\n"); + if (test[TestCap]) + printf("\ttest VIDIOC_QUERYCAP: %s\n", ok(testCap(fd))); + + printf("Debug ioctls:\n"); + if (test[TestChipIdent]) + printf("\ttest VIDIOC_G_CHIP_IDENT: %s\n", ok(testChipIdent(fd))); + if (test[TestRegister]) + printf("\ttest VIDIOC_DBG_G/S_REGISTER: %s\n", ok(testRegister(fd))); + if (test[TestLogStatus]) + printf("\ttest VIDIOC_LOG_STATUS: %s\n", ok(testLogStatus(fd))); + + close(fd); + exit(app_result); +} diff --git a/v4l2-apps/util/v4l2-ctl.cpp b/v4l2-apps/util/v4l2-ctl.cpp index ae9293414..1c765cf96 100644 --- a/v4l2-apps/util/v4l2-ctl.cpp +++ b/v4l2-apps/util/v4l2-ctl.cpp @@ -93,6 +93,7 @@ enum Option { OptListFormats, OptLogStatus, OptVerbose, + OptSilent, OptGetVideoOutFormat, OptSetVideoOutFormat, OptGetSlicedVbiCap, @@ -291,15 +292,15 @@ static void usage(void) " set the video capture format [VIDIOC_S_FMT]\n" " pixelformat is either the format index as reported by\n" " --list-formats, or the fourcc value as a string\n" - " --verbose turn on verbose ioctl error reporting.\n" + " --silent only set the result code, do not print any messages\n" + " --verbose turn on verbose ioctl status reporting\n" "\n"); printf("Uncommon options:\n" " --get-fmt-video-out\n" " query the video output format [VIDIOC_G_FMT]\n" " --set-fmt-video-out=width=<w>,height=<h>\n" " set the video output format [VIDIOC_S_FMT]\n" - " --get-fmt-overlay\n" - " query the video overlay format [VIDIOC_G_FMT]\n" + " --get-fmt-overlay query the video overlay format [VIDIOC_G_FMT]\n" " --get-fmt-output-overlay\n" " query the video output overlay format [VIDIOC_G_FMT]\n" " --set-fmt-output-overlay=chromakey=<key>,global_alpha=<alpha>\n" @@ -1017,12 +1018,11 @@ static int doioctl(int fd, int request, void *parm, const char *name) if (retVal < 0) { app_result = -1; } - if (!options[OptVerbose]) return retVal; - printf("%s: ", name); + if (options[OptSilent]) return retVal; if (retVal < 0) - printf("failed: %s\n", strerror(errno)); - else - printf("ok\n"); + printf("%s: failed: %s\n", name, strerror(errno)); + else if (options[OptVerbose]) + printf("%s: ok\n", name); return retVal; } diff --git a/v4l2-apps/util/bttv-dbg.h b/v4l2-apps/util/v4l2-dbg-bttv.h index 02f829773..cf6274284 100644 --- a/v4l2-apps/util/bttv-dbg.h +++ b/v4l2-apps/util/v4l2-dbg-bttv.h @@ -14,7 +14,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "v4l-board-dbg.h" +#include "v4l2-dbg.h" #define BTTV_IDENT "bttv" diff --git a/v4l2-apps/util/em28xx-dbg.h b/v4l2-apps/util/v4l2-dbg-em28xx.h index 3d3600c44..c5117c6e7 100644 --- a/v4l2-apps/util/em28xx-dbg.h +++ b/v4l2-apps/util/v4l2-dbg-em28xx.h @@ -14,7 +14,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "v4l-board-dbg.h" +#include "v4l2-dbg.h" #define EM28XX_IDENT "em28xx" diff --git a/v4l2-apps/util/saa7134-dbg.h b/v4l2-apps/util/v4l2-dbg-saa7134.h index aee29da76..70fd4e068 100644 --- a/v4l2-apps/util/saa7134-dbg.h +++ b/v4l2-apps/util/v4l2-dbg-saa7134.h @@ -14,7 +14,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "v4l-board-dbg.h" +#include "v4l2-dbg.h" #define SAA7134_IDENT "saa7134" diff --git a/v4l2-apps/util/v4l2-dbg.cpp b/v4l2-apps/util/v4l2-dbg.cpp index 2561f42b2..e0d6153fe 100644 --- a/v4l2-apps/util/v4l2-dbg.cpp +++ b/v4l2-apps/util/v4l2-dbg.cpp @@ -42,6 +42,48 @@ #include <map> #include <string> +#include "v4l2-dbg-bttv.h" +#include "v4l2-dbg-saa7134.h" +#include "v4l2-dbg-em28xx.h" + +#define ARRAY_SIZE(arr) ((int)(sizeof(arr) / sizeof((arr)[0]))) + +struct board_list { + const char *name; + int prefix; /* Register prefix size */ + const struct board_regs *regs; + int regs_size; + const struct board_regs *alt_regs; + int alt_regs_size; +}; + +static const struct board_list boards[] = { + { /* From bttv-dbg.h */ + BTTV_IDENT, + sizeof(BTTV_PREFIX) - 1, + bt8xx_regs, + ARRAY_SIZE(bt8xx_regs), + bt8xx_regs_other, + ARRAY_SIZE(bt8xx_regs_other), + }, + { /* From saa7134-dbg.h */ + SAA7134_IDENT, + sizeof(SAA7134_PREFIX) - 1, + saa7134_regs, + ARRAY_SIZE(saa7134_regs), + NULL, + 0, + }, + { /* From em28xx-dbg.h */ + EM28XX_IDENT, + sizeof(EM28XX_PREFIX) - 1, + em28xx_regs, + ARRAY_SIZE(em28xx_regs), + NULL, + 0, + }, +}; + struct driverid { const char *name; unsigned id; @@ -64,19 +106,21 @@ extern struct chipid chipids[]; In general the lower case is used to set something and the upper case is used to retrieve a setting. */ enum Option { - OptListRegisters = 'R', - OptSetRegister = 'r', - OptSetSlicedVbiFormat = 'b', + OptListRegisters = 'l', + OptGetRegister = 'g', + OptSetRegister = 's', OptSetDevice = 'd', OptGetDriverInfo = 'D', - OptScanChipIdents = 'C', - OptGetChipIdent = 'c', + OptChip = 'c', + OptScanChipIdents = 'S', + OptGetChipIdent = 'i', OptSetStride = 'w', OptHelp = 'h', OptLogStatus = 128, OptVerbose, OptListDriverIDs, + OptListSymbols, OptLast = 256 }; @@ -87,56 +131,56 @@ static unsigned capabilities; static struct option long_options[] = { {"device", required_argument, 0, OptSetDevice}, {"help", no_argument, 0, OptHelp}, - {"list-registers", required_argument, 0, OptListRegisters}, + {"list-registers", optional_argument, 0, OptListRegisters}, + {"get-register", required_argument, 0, OptGetRegister}, {"set-register", required_argument, 0, OptSetRegister}, + {"chip", required_argument, 0, OptChip}, {"scan-chip-idents", no_argument, 0, OptScanChipIdents}, {"get-chip-ident", required_argument, 0, OptGetChipIdent}, {"info", no_argument, 0, OptGetDriverInfo}, {"verbose", no_argument, 0, OptVerbose}, {"log-status", no_argument, 0, OptLogStatus}, {"list-driverids", no_argument, 0, OptListDriverIDs}, + {"list-symbols", no_argument, 0, OptListSymbols}, {"wide", required_argument, 0, OptSetStride}, {0, 0, 0, 0} }; static void usage(void) { - printf("Usage:\n"); - printf(" -D, --info show driver info [VIDIOC_QUERYCAP]\n"); - printf(" -d, --device=<dev> use device <dev> instead of /dev/video0\n"); - printf(" if <dev> is a single digit, then /dev/video<dev> is used\n"); - printf(" -h, --help display this help message\n"); - printf(" --verbose turn on verbose ioctl error reporting.\n"); - printf(" -R, --list-registers=type=<host/i2cdrv/i2caddr>,chip=<chip>[,min=<addr>,max=<addr>] \n"); - printf(" dump registers from <min> to <max> [VIDIOC_DBG_G_REGISTER]\n"); - printf(" -r, --set-register=type=<host/i2cdrv/i2caddr>,chip=<chip>,reg=<addr>,val=<val>\n"); - printf(" set the register [VIDIOC_DBG_S_REGISTER]\n"); - printf(" -C, --scan-chip-idents\n"); - printf(" Scan the available host and i2c chips [VIDIOC_G_CHIP_IDENT]\n"); - printf(" -c, --get-chip-ident=type=<host/i2cdrv/i2caddr>,chip=<chip>\n"); - printf(" Get the chip identifier [VIDIOC_G_CHIP_IDENT]\n"); - printf(" -w, --wide=<reg length>\n"); - printf(" Sets step between two registers\n"); - printf(" --log-status log the board status in the kernel log [VIDIOC_LOG_STATUS]\n"); - printf(" --list-driverids list the known I2C driver IDs for use with the i2cdrv type\n"); - printf("\n"); - printf(" if type == host, then <chip> is the host's chip ID (default 0)\n"); - printf(" if type == i2cdrv (default), then <chip> is the I2C driver name or ID\n"); - printf(" if type == i2caddr, then <chip> is the 7-bit I2C address\n"); + printf("Usage: v4l2-dbg [options] [values]\n" + " -D, --info Show driver info [VIDIOC_QUERYCAP]\n" + " -d, --device=<dev> Use device <dev> instead of /dev/video0\n" + " If <dev> is a single digit, then /dev/video<dev> is used\n" + " -h, --help Display this help message\n" + " --verbose Turn on verbose ioctl error reporting\n" + " -c, --chip=<chip> The chip identifier to use with other commands\n" + " It can be one of:\n" + " I2C driver ID (see --list-driverids)\n" + " I2C 7-bit address\n" + " host<num>: host chip number <num>\n" + " host (default): same as host0\n" + " -l, --list-registers[=min=<addr>[,max=<addr>]]\n" + " Dump registers from <min> to <max> [VIDIOC_DBG_G_REGISTER]\n" + " -g, --get-register=<addr>\n" + " Get the specified register [VIDIOC_DBG_G_REGISTER]\n" + " -s, --set-register=<addr>\n" + " Set the register with the commandline arguments\n" + " The register will autoincrement [VIDIOC_DBG_S_REGISTER]\n" + " -S, --scan-chip-idents\n" + " Scan the available host and i2c chips [VIDIOC_G_CHIP_IDENT]\n" + " -i, --get-chip-ident\n" + " Get the chip identifier [VIDIOC_G_CHIP_IDENT]\n" + " -w, --wide=<reg length>\n" + " Sets step between two registers\n" + " --list-symbols List the symbolic register names you can use, if any\n" + " --log-status Log the board status in the kernel log [VIDIOC_LOG_STATUS]\n" + " --list-driverids List the known I2C driver IDs for use with the i2cdrv type\n"); exit(0); } -static unsigned parse_type(const std::string &s) -{ - if (s == "host") return V4L2_CHIP_MATCH_HOST; - if (s == "i2caddr") return V4L2_CHIP_MATCH_I2C_ADDR; - return V4L2_CHIP_MATCH_I2C_DRIVER; -} - -static unsigned parse_chip(int type, const std::string &s) +static unsigned parse_chip(const std::string &s) { - if (type == V4L2_CHIP_MATCH_HOST || type == V4L2_CHIP_MATCH_I2C_ADDR || isdigit(s[0])) - return strtoul(s.c_str(), 0, 0); for (int i = 0; driverids[i].name; i++) if (!strcasecmp(s.c_str(), driverids[i].name)) return driverids[i].id; @@ -230,6 +274,56 @@ static void print_chip(struct v4l2_chip_ident *chip) printf("%-10d revision 0x%08x\n", chip->ident, chip->revision); } +static unsigned long long parse_reg(const struct board_list *curr_bd, const std::string ®) +{ + if (curr_bd) { + for (int i = 0; i < curr_bd->regs_size; i++) { + if (!strcasecmp(reg.c_str(), curr_bd->regs[i].name) || + !strcasecmp(reg.c_str(), curr_bd->regs[i].name + curr_bd->prefix)) { + return curr_bd->regs[i].reg; + } + } + for (int i = 0; i < curr_bd->alt_regs_size; i++) { + if (!strcasecmp(reg.c_str(), curr_bd->alt_regs[i].name) || + !strcasecmp(reg.c_str(), curr_bd->alt_regs[i].name + curr_bd->prefix)) { + return curr_bd->alt_regs[i].reg; + } + } + } + return strtoull(reg.c_str(), NULL, 0); +} + +static const char *binary(unsigned long long val) +{ + static char bin[80]; + char *p = bin; + int i, j; + int bits = 64; + + if ((val & 0xffffffff00000000LL) == 0) { + if ((val & 0xffff0000) == 0) { + if ((val & 0xff00) == 0) + bits = 8; + else + bits= 16; + } + else + bits = 32; + } + + for (i = bits - 1; i >= 0; i -= 8) { + for (j = i; j >= i - 7; j--) { + if (val & (1LL << j)) + *p++ = '1'; + else + *p++ = '0'; + } + *p++ = ' '; + } + p[-1] = 0; + return bin; +} + static int doioctl(int fd, int request, void *parm, const char *name) { int retVal; @@ -277,9 +371,15 @@ int main(int argc, char **argv) struct v4l2_register set_reg; struct v4l2_register get_reg; struct v4l2_chip_ident chip_id; + const struct board_list *curr_bd = NULL; char short_options[26 * 2 * 2 + 1]; int idx = 0; + std::string reg_min_arg, reg_max_arg; + std::string reg_set_arg; unsigned long long reg_min = 0, reg_max = 0; + std::vector<std::string> get_regs; + int match_type = V4L2_CHIP_MATCH_HOST; + int match_chip = 0; memset(&set_reg, 0, sizeof(set_reg)); memset(&get_reg, 0, sizeof(get_reg)); @@ -310,6 +410,7 @@ int main(int argc, char **argv) case OptHelp: usage(); return 0; + case OptSetDevice: device = optarg; if (device[0] >= '0' && device[0] <= '9' && device[1] == 0) { @@ -320,43 +421,44 @@ int main(int argc, char **argv) device = newdev; } break; - case OptSetRegister: - subs = optarg; - set_reg.match_type = V4L2_CHIP_MATCH_I2C_DRIVER; - while (*subs != '\0') { - static const char * const subopts[] = { - "type", - "chip", - "reg", - "val", - NULL - }; - switch (parse_subopt(&subs, subopts, &value)) { - case 0: - set_reg.match_type = parse_type(value); - break; - case 1: - set_reg.match_chip = parse_chip(set_reg.match_type, value); - break; - case 2: - set_reg.reg = strtoull(value, 0L, 0); - break; - case 3: - set_reg.val = strtoull(value, 0L, 0); - break; - } + case OptChip: + if (isdigit(optarg[0])) { + match_type = V4L2_CHIP_MATCH_I2C_ADDR; + match_chip = strtoul(optarg, NULL, 0); + break; + } + if (!memcmp(optarg, "host", 4)) { + match_type = V4L2_CHIP_MATCH_HOST; + match_chip = strtoul(optarg + 4, NULL, 0); + break; } + match_type = V4L2_CHIP_MATCH_I2C_DRIVER; + match_chip = parse_chip(optarg); + if (!match_chip) { + fprintf(stderr, "unknown driver ID %s\n", optarg); + exit(-1); + } + break; + + case OptSetRegister: + reg_set_arg = optarg; + break; + + case OptGetRegister: + get_regs.push_back(optarg); + break; + case OptSetStride: forcedstride = strtoull(optarg, 0L, 0); break; + case OptListRegisters: subs = optarg; - get_reg.match_type = V4L2_CHIP_MATCH_I2C_DRIVER; + if (subs == NULL) + break; while (*subs != '\0') { static const char * const subopts[] = { - "type", - "chip", "min", "max", NULL @@ -364,47 +466,27 @@ int main(int argc, char **argv) switch (parse_subopt(&subs, subopts, &value)) { case 0: - get_reg.match_type = parse_type(value); + reg_min_arg = value; + //if (reg_max == 0) + // reg_max = reg_min + 0xff; break; case 1: - get_reg.match_chip = parse_chip(get_reg.match_type, value); - break; - case 2: - reg_min = strtoull(value, 0L, 0); - if (reg_max == 0) - reg_max = reg_min + 0xff; - break; - case 3: - reg_max = strtoull(value, 0L, 0); + reg_max_arg = value; break; } } break; - case OptGetChipIdent: - subs = optarg; - set_reg.match_type = V4L2_CHIP_MATCH_I2C_DRIVER; - while (*subs != '\0') { - static const char *const subopts[] = { - "type", - "chip", - NULL - }; - switch (parse_subopt(&subs, subopts, &value)) { - case 0: - chip_id.match_type = parse_type(value); - break; - case 1: - chip_id.match_chip = parse_chip(chip_id.match_type, value); - break; - } - } + case OptGetChipIdent: + case OptListSymbols: break; + case ':': fprintf(stderr, "Option `%s' requires a value\n", argv[optind]); usage(); return 1; + case '?': fprintf(stderr, "Unknown argument `%s'\n", argv[optind]); @@ -412,14 +494,6 @@ int main(int argc, char **argv) return 1; } } - if (optind < argc) { - printf("unknown arguments: "); - while (optind < argc) - printf("%s ", argv[optind++]); - printf("\n"); - usage(); - return 1; - } if ((fd = open(device, O_RDWR)) < 0) { fprintf(stderr, "Failed to open %s: %s\n", device, @@ -442,15 +516,33 @@ int main(int argc, char **argv) printf("%s", cap2s(vcap.capabilities).c_str()); } + for (int board = ARRAY_SIZE(boards) - 1; board >= 0; board--) { + if (!strcasecmp((char *)vcap.driver, boards[board].name)) { + curr_bd = &boards[board]; + break; + } + } + /* Set options */ if (options[OptSetRegister]) { - if (doioctl(fd, VIDIOC_DBG_S_REGISTER, &set_reg, - "VIDIOC_DBG_S_REGISTER") == 0) - printf("register 0x%llx set to 0x%llx\n", set_reg.reg, set_reg.val); + set_reg.match_type = match_type; + set_reg.match_chip = match_chip; + if (optind >= argc) + usage(); + set_reg.reg = parse_reg(curr_bd, reg_set_arg); + while (optind < argc) { + set_reg.val = strtoull(argv[optind++], NULL, 0); + if (doioctl(fd, VIDIOC_DBG_S_REGISTER, &set_reg, + "VIDIOC_DBG_S_REGISTER") == 0) + printf("register 0x%llx set to 0x%llx\n", set_reg.reg, set_reg.val); + set_reg.reg++; + } } if (options[OptGetChipIdent]) { + chip_id.match_type = match_type; + chip_id.match_chip = match_chip; if (doioctl(fd, VIDIOC_G_CHIP_IDENT, &chip_id, "VIDIOC_G_CHIP_IDENT") == 0) print_chip(&chip_id); } @@ -462,7 +554,7 @@ int main(int argc, char **argv) chip_id.match_chip = 0; while (doioctl(fd, VIDIOC_G_CHIP_IDENT, &chip_id, "VIDIOC_G_CHIP_IDENT") == 0 && chip_id.ident) { - printf("host 0x%x: ", chip_id.match_chip); + printf("host%d: ", chip_id.match_chip); print_chip(&chip_id); chip_id.match_chip++; } @@ -477,8 +569,30 @@ int main(int argc, char **argv) } } + if (options[OptGetRegister]) { + int stride = 1; + + get_reg.match_type = match_type; + get_reg.match_chip = match_chip; + printf("ioctl: VIDIOC_DBG_G_REGISTER\n"); + + for (std::vector<std::string>::iterator iter = get_regs.begin(); + iter != get_regs.end(); ++iter) { + get_reg.reg = parse_reg(curr_bd, *iter); + if (ioctl(fd, VIDIOC_DBG_G_REGISTER, &get_reg) < 0) + fprintf(stderr, "ioctl: VIDIOC_DBG_G_REGISTER " + "failed for 0x%llx\n", get_reg.reg); + else + printf("%llx = %llxh = %lldd = %sb\n", get_reg.reg, + get_reg.val, get_reg.val, binary(get_reg.val)); + } + } + if (options[OptListRegisters]) { int stride = 1; + + get_reg.match_type = match_type; + get_reg.match_chip = match_chip; if (forcedstride) { stride = forcedstride; } else { @@ -487,7 +601,12 @@ int main(int argc, char **argv) } printf("ioctl: VIDIOC_DBG_G_REGISTER\n"); - if (reg_max != 0) { + if (!reg_min_arg.empty()) { + reg_min = parse_reg(curr_bd, reg_min_arg); + if (reg_max_arg.empty()) + reg_max = reg_min + 0xff; + else + reg_max = parse_reg(curr_bd, reg_max_arg); /* Explicit memory range: just do it */ print_regs(fd, &get_reg, reg_min, reg_max, stride); goto list_done; @@ -580,6 +699,19 @@ list_done: printf("%s\n", driverids[i].name); } + if (options[OptListSymbols]) { + if (curr_bd == NULL) { + printf("No symbols found for driver %s\n", vcap.driver); + } + else { + printf("Symbols for driver %s:\n", vcap.driver); + for (int i = 0; i < curr_bd->regs_size; i++) + printf("0x%08x: %s\n", curr_bd->regs[i], curr_bd->regs[i].name); + for (int i = 0; i < curr_bd->alt_regs_size; i++) + printf("0x%08x: %s\n", curr_bd->alt_regs[i], curr_bd->alt_regs[i].name); + } + } + close(fd); exit(0); } diff --git a/v4l2-apps/util/v4l-board-dbg.h b/v4l2-apps/util/v4l2-dbg.h index d7e7a9ef3..06ceb0ea2 100644 --- a/v4l2-apps/util/v4l-board-dbg.h +++ b/v4l2-apps/util/v4l2-dbg.h @@ -14,11 +14,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#ifndef _V4L_BOARD_DBG -#define _V4L_BOARD_DBG +#ifndef _V4L2_DBG_H_ +#define _V4L2_DBG_H_ + struct board_regs { unsigned int reg; - char *name; + const char *name; int size; }; + #endif diff --git a/v4l2-apps/util/xc3028-firmware/Makefile b/v4l2-apps/util/xc3028-firmware/Makefile index 102f712fd..6894e984e 100644 --- a/v4l2-apps/util/xc3028-firmware/Makefile +++ b/v4l2-apps/util/xc3028-firmware/Makefile @@ -1,6 +1,6 @@ # Makefile for linuxtv.org v4l2-apps/util/xc3028-firmware -CPPFLAGS += -I../../../linux/include +CPPFLAGS += -I../../include binaries = firmware-tool |