diff options
Diffstat (limited to 'drivers/media/video/gspca')
35 files changed, 1877 insertions, 2648 deletions
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile index 79ebe46e1ad..c901da0bd65 100644 --- a/drivers/media/video/gspca/Makefile +++ b/drivers/media/video/gspca/Makefile @@ -43,7 +43,7 @@ obj-$(CONFIG_USB_GSPCA_VICAM) += gspca_vicam.o obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o -gspca_main-objs := gspca.o +gspca_main-objs := gspca.o autogain_functions.o gspca_benq-objs := benq.o gspca_conex-objs := conex.o gspca_cpia1-objs := cpia1.o diff --git a/drivers/media/video/gspca/autogain_functions.c b/drivers/media/video/gspca/autogain_functions.c new file mode 100644 index 00000000000..67db674bb04 --- /dev/null +++ b/drivers/media/video/gspca/autogain_functions.c @@ -0,0 +1,178 @@ +/* + * Functions for auto gain. + * + * Copyright (C) 2010-2012 Hans de Goede <hdegoede@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "gspca.h" + +/* auto gain and exposure algorithm based on the knee algorithm described here: + http://ytse.tricolour.net/docs/LowLightOptimization.html + + Returns 0 if no changes were made, 1 if the gain and or exposure settings + where changed. */ +int gspca_expo_autogain( + struct gspca_dev *gspca_dev, + int avg_lum, + int desired_avg_lum, + int deadzone, + int gain_knee, + int exposure_knee) +{ + s32 gain, orig_gain, exposure, orig_exposure; + int i, steps, retval = 0; + + if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0) + return 0; + + orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain); + orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure); + + /* If we are of a multiple of deadzone, do multiple steps to reach the + desired lumination fast (with the risc of a slight overshoot) */ + steps = abs(desired_avg_lum - avg_lum) / deadzone; + + PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", + avg_lum, desired_avg_lum, steps); + + for (i = 0; i < steps; i++) { + if (avg_lum > desired_avg_lum) { + if (gain > gain_knee) + gain--; + else if (exposure > exposure_knee) + exposure--; + else if (gain > gspca_dev->gain->default_value) + gain--; + else if (exposure > gspca_dev->exposure->minimum) + exposure--; + else if (gain > gspca_dev->gain->minimum) + gain--; + else + break; + } else { + if (gain < gspca_dev->gain->default_value) + gain++; + else if (exposure < exposure_knee) + exposure++; + else if (gain < gain_knee) + gain++; + else if (exposure < gspca_dev->exposure->maximum) + exposure++; + else if (gain < gspca_dev->gain->maximum) + gain++; + else + break; + } + } + + if (gain != orig_gain) { + v4l2_ctrl_s_ctrl(gspca_dev->gain, gain); + retval = 1; + } + if (exposure != orig_exposure) { + v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure); + retval = 1; + } + + if (retval) + PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d", + gain, exposure); + return retval; +} +EXPORT_SYMBOL(gspca_expo_autogain); + +/* Autogain + exposure algorithm for cameras with a coarse exposure control + (usually this means we can only control the clockdiv to change exposure) + As changing the clockdiv so that the fps drops from 30 to 15 fps for + example, will lead to a huge exposure change (it effectively doubles), + this algorithm normally tries to only adjust the gain (between 40 and + 80 %) and if that does not help, only then changes exposure. This leads + to a much more stable image then using the knee algorithm which at + certain points of the knee graph will only try to adjust exposure, + which leads to oscilating as one exposure step is huge. + + Returns 0 if no changes were made, 1 if the gain and or exposure settings + where changed. */ +int gspca_coarse_grained_expo_autogain( + struct gspca_dev *gspca_dev, + int avg_lum, + int desired_avg_lum, + int deadzone) +{ + s32 gain_low, gain_high, gain, orig_gain, exposure, orig_exposure; + int steps, retval = 0; + + if (v4l2_ctrl_g_ctrl(gspca_dev->autogain) == 0) + return 0; + + orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain); + orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure); + + gain_low = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) / + 5 * 2 + gspca_dev->gain->minimum; + gain_high = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) / + 5 * 4 + gspca_dev->gain->minimum; + + /* If we are of a multiple of deadzone, do multiple steps to reach the + desired lumination fast (with the risc of a slight overshoot) */ + steps = (desired_avg_lum - avg_lum) / deadzone; + + PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", + avg_lum, desired_avg_lum, steps); + + if ((gain + steps) > gain_high && + exposure < gspca_dev->exposure->maximum) { + gain = gain_high; + gspca_dev->exp_too_low_cnt++; + gspca_dev->exp_too_high_cnt = 0; + } else if ((gain + steps) < gain_low && + exposure > gspca_dev->exposure->minimum) { + gain = gain_low; + gspca_dev->exp_too_high_cnt++; + gspca_dev->exp_too_low_cnt = 0; + } else { + gain += steps; + if (gain > gspca_dev->gain->maximum) + gain = gspca_dev->gain->maximum; + else if (gain < gspca_dev->gain->minimum) + gain = gspca_dev->gain->minimum; + gspca_dev->exp_too_high_cnt = 0; + gspca_dev->exp_too_low_cnt = 0; + } + + if (gspca_dev->exp_too_high_cnt > 3) { + exposure--; + gspca_dev->exp_too_high_cnt = 0; + } else if (gspca_dev->exp_too_low_cnt > 3) { + exposure++; + gspca_dev->exp_too_low_cnt = 0; + } + + if (gain != orig_gain) { + v4l2_ctrl_s_ctrl(gspca_dev->gain, gain); + retval = 1; + } + if (exposure != orig_exposure) { + v4l2_ctrl_s_ctrl(gspca_dev->exposure, exposure); + retval = 1; + } + + if (retval) + PDEBUG(D_FRAM, "autogain: changed gain: %d, expo: %d", + gain, exposure); + return retval; +} +EXPORT_SYMBOL(gspca_coarse_grained_expo_autogain); diff --git a/drivers/media/video/gspca/autogain_functions.h b/drivers/media/video/gspca/autogain_functions.h index 46777eee678..d625eafe63e 100644 --- a/drivers/media/video/gspca/autogain_functions.h +++ b/drivers/media/video/gspca/autogain_functions.h @@ -18,6 +18,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#ifdef WANT_REGULAR_AUTOGAIN /* auto gain and exposure algorithm based on the knee algorithm described here: http://ytse.tricolour.net/docs/LowLightOptimization.html @@ -91,7 +92,9 @@ static inline int auto_gain_n_exposure( gain, exposure); return retval; } +#endif +#ifdef WANT_COARSE_EXPO_AUTOGAIN /* Autogain + exposure algorithm for cameras with a coarse exposure control (usually this means we can only control the clockdiv to change exposure) As changing the clockdiv so that the fps drops from 30 to 15 fps for @@ -103,7 +106,7 @@ static inline int auto_gain_n_exposure( which leads to oscilating as one exposure step is huge. Note this assumes that the sd struct for the cam in question has - exp_too_high_cnt and exp_too_high_cnt int members for use by this function. + exp_too_low_cnt and exp_too_high_cnt int members for use by this function. Returns 0 if no changes were made, 1 if the gain and or exposure settings where changed. */ @@ -177,3 +180,4 @@ static inline int coarse_grained_expo_autogain( gain, exposure); return retval; } +#endif diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c index ea17b5d94ea..f39fee0fd10 100644 --- a/drivers/media/video/gspca/conex.c +++ b/drivers/media/video/gspca/conex.c @@ -306,7 +306,7 @@ static void cx_sensor(struct gspca_dev*gspca_dev) reg_w(gspca_dev, 0x0020, reg20, 8); reg_w(gspca_dev, 0x0028, reg28, 8); - reg_w(gspca_dev, 0x0010, reg10, 8); + reg_w(gspca_dev, 0x0010, reg10, 2); reg_w_val(gspca_dev, 0x0092, 0x03); switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { @@ -326,7 +326,7 @@ static void cx_sensor(struct gspca_dev*gspca_dev) } reg_w(gspca_dev, 0x007b, reg7b, 6); reg_w_val(gspca_dev, 0x00f8, 0x00); - reg_w(gspca_dev, 0x0010, reg10, 8); + reg_w(gspca_dev, 0x0010, reg10, 2); reg_w_val(gspca_dev, 0x0098, 0x41); for (i = 0; i < 11; i++) { if (i == 3 || i == 5 || i == 8) diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c index 0107513cd72..6e26c93b465 100644 --- a/drivers/media/video/gspca/finepix.c +++ b/drivers/media/video/gspca/finepix.c @@ -94,7 +94,11 @@ static void dostream(struct work_struct *work) /* loop reading a frame */ again: - while (gspca_dev->present && gspca_dev->streaming) { + while (gspca_dev->dev && gspca_dev->streaming) { +#ifdef CONFIG_PM + if (gspca_dev->frozen) + break; +#endif /* request a frame */ mutex_lock(&gspca_dev->usb_lock); @@ -102,7 +106,11 @@ again: mutex_unlock(&gspca_dev->usb_lock); if (ret < 0) break; - if (!gspca_dev->present || !gspca_dev->streaming) +#ifdef CONFIG_PM + if (gspca_dev->frozen) + break; +#endif + if (!gspca_dev->dev || !gspca_dev->streaming) break; /* the frame comes in parts */ @@ -117,7 +125,11 @@ again: * error. Just restart. */ goto again; } - if (!gspca_dev->present || !gspca_dev->streaming) +#ifdef CONFIG_PM + if (gspca_dev->frozen) + goto out; +#endif + if (!gspca_dev->dev || !gspca_dev->streaming) goto out; if (len < FPIX_MAX_TRANSFER || (data[len - 2] == 0xff && diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c index c84e26006fc..c549574c1c7 100644 --- a/drivers/media/video/gspca/gl860/gl860.c +++ b/drivers/media/video/gspca/gl860/gl860.c @@ -405,6 +405,9 @@ static void sd_stop0(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + if (!sd->gspca_dev.present) + return; + return sd->dev_post_unset_alt(gspca_dev); } diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c index ca5a2b139d0..137166d7394 100644 --- a/drivers/media/video/gspca/gspca.c +++ b/drivers/media/video/gspca/gspca.c @@ -38,6 +38,9 @@ #include <linux/uaccess.h> #include <linux/ktime.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-fh.h> +#include <media/v4l2-event.h> #include "gspca.h" @@ -592,16 +595,13 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev) static void gspca_stream_off(struct gspca_dev *gspca_dev) { gspca_dev->streaming = 0; - if (gspca_dev->present) { - if (gspca_dev->sd_desc->stopN) - gspca_dev->sd_desc->stopN(gspca_dev); - destroy_urbs(gspca_dev); - gspca_input_destroy_urb(gspca_dev); - gspca_set_alt0(gspca_dev); - gspca_input_create_urb(gspca_dev); - } - - /* always call stop0 to free the subdriver's resources */ + gspca_dev->usb_err = 0; + if (gspca_dev->sd_desc->stopN) + gspca_dev->sd_desc->stopN(gspca_dev); + destroy_urbs(gspca_dev); + gspca_input_destroy_urb(gspca_dev); + gspca_set_alt0(gspca_dev); + gspca_input_create_urb(gspca_dev); if (gspca_dev->sd_desc->stop0) gspca_dev->sd_desc->stop0(gspca_dev); PDEBUG(D_STREAM, "stream off OK"); @@ -847,14 +847,6 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) struct ep_tb_s ep_tb[MAX_ALT]; int n, ret, xfer, alt, alt_idx; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - - if (!gspca_dev->present) { - ret = -ENODEV; - goto unlock; - } - /* reset the streaming variables */ gspca_dev->image = NULL; gspca_dev->image_len = 0; @@ -869,7 +861,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) if (gspca_dev->sd_desc->isoc_init) { ret = gspca_dev->sd_desc->isoc_init(gspca_dev); if (ret < 0) - goto unlock; + return ret; } xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK : USB_ENDPOINT_XFER_ISOC; @@ -880,8 +872,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer); if (ep == NULL) { pr_err("bad altsetting %d\n", gspca_dev->alt); - ret = -EIO; - goto out; + return -EIO; } ep_tb[0].alt = gspca_dev->alt; alt_idx = 1; @@ -892,8 +883,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb); if (alt_idx <= 0) { pr_err("no transfer endpoint found\n"); - ret = -EIO; - goto unlock; + return -EIO; } } @@ -988,8 +978,6 @@ retry: } out: gspca_input_create_urb(gspca_dev); -unlock: - mutex_unlock(&gspca_dev->usb_lock); return ret; } @@ -1006,6 +994,8 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev) /* set the current control values to their default values * which may have changed in sd_init() */ + /* does nothing if ctrl_handler == NULL */ + v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler); ctrl = gspca_dev->cam.ctrls; if (ctrl != NULL) { for (i = 0; @@ -1057,77 +1047,50 @@ static int gspca_get_mode(struct gspca_dev *gspca_dev, static int vidioc_g_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { - int ret; - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); if (!gspca_dev->sd_desc->get_chip_ident) - return -EINVAL; + return -ENOTTY; if (!gspca_dev->sd_desc->get_register) - return -EINVAL; + return -ENOTTY; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; gspca_dev->usb_err = 0; - if (gspca_dev->present) - ret = gspca_dev->sd_desc->get_register(gspca_dev, reg); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - - return ret; + return gspca_dev->sd_desc->get_register(gspca_dev, reg); } static int vidioc_s_register(struct file *file, void *priv, struct v4l2_dbg_register *reg) { - int ret; - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); if (!gspca_dev->sd_desc->get_chip_ident) - return -EINVAL; + return -ENOTTY; if (!gspca_dev->sd_desc->set_register) - return -EINVAL; + return -ENOTTY; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; gspca_dev->usb_err = 0; - if (gspca_dev->present) - ret = gspca_dev->sd_desc->set_register(gspca_dev, reg); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - - return ret; + return gspca_dev->sd_desc->set_register(gspca_dev, reg); } #endif static int vidioc_g_chip_ident(struct file *file, void *priv, struct v4l2_dbg_chip_ident *chip) { - int ret; - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); if (!gspca_dev->sd_desc->get_chip_ident) - return -EINVAL; + return -ENOTTY; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; gspca_dev->usb_err = 0; - if (gspca_dev->present) - ret = gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - - return ret; + return gspca_dev->sd_desc->get_chip_ident(gspca_dev, chip); } static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *fmtdesc) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); int i, j, index; __u32 fmt_tb[8]; @@ -1169,7 +1132,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 *fmt) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); int mode; mode = gspca_dev->curr_mode; @@ -1214,7 +1177,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); int ret; ret = try_fmt_vid_cap(gspca_dev, fmt); @@ -1226,7 +1189,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *fmt) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); int ret; if (mutex_lock_interruptible(&gspca_dev->queue_lock)) @@ -1265,7 +1228,7 @@ out: static int vidioc_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); int i; __u32 index = 0; @@ -1291,7 +1254,7 @@ static int vidioc_enum_framesizes(struct file *file, void *priv, static int vidioc_enum_frameintervals(struct file *filp, void *priv, struct v4l2_frmivalenum *fival) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(filp); int mode = wxh_to_mode(gspca_dev, fival->width, fival->height); __u32 i; @@ -1316,31 +1279,30 @@ static int vidioc_enum_frameintervals(struct file *filp, void *priv, return -EINVAL; } -static void gspca_release(struct video_device *vfd) +static void gspca_release(struct v4l2_device *v4l2_device) { - struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev); + struct gspca_dev *gspca_dev = + container_of(v4l2_device, struct gspca_dev, v4l2_dev); PDEBUG(D_PROBE, "%s released", video_device_node_name(&gspca_dev->vdev)); + v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler); + v4l2_device_unregister(&gspca_dev->v4l2_dev); kfree(gspca_dev->usb_buf); kfree(gspca_dev); } static int dev_open(struct file *file) { - struct gspca_dev *gspca_dev; + struct gspca_dev *gspca_dev = video_drvdata(file); PDEBUG(D_STREAM, "[%s] open", current->comm); - gspca_dev = (struct gspca_dev *) video_devdata(file); - if (!gspca_dev->present) - return -ENODEV; /* protect the subdriver against rmmod */ if (!try_module_get(gspca_dev->module)) return -ENODEV; - file->private_data = gspca_dev; #ifdef GSPCA_DEBUG /* activate the v4l2 debug */ if (gspca_debug & D_V4L2) @@ -1350,49 +1312,44 @@ static int dev_open(struct file *file) gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG); #endif - return 0; + return v4l2_fh_open(file); } static int dev_close(struct file *file) { - struct gspca_dev *gspca_dev = file->private_data; + struct gspca_dev *gspca_dev = video_drvdata(file); PDEBUG(D_STREAM, "[%s] close", current->comm); - if (mutex_lock_interruptible(&gspca_dev->queue_lock)) + + /* Needed for gspca_stream_off, always lock before queue_lock! */ + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) return -ERESTARTSYS; + if (mutex_lock_interruptible(&gspca_dev->queue_lock)) { + mutex_unlock(&gspca_dev->usb_lock); + return -ERESTARTSYS; + } + /* if the file did the capture, free the streaming resources */ if (gspca_dev->capt_file == file) { - if (gspca_dev->streaming) { - mutex_lock(&gspca_dev->usb_lock); - gspca_dev->usb_err = 0; + if (gspca_dev->streaming) gspca_stream_off(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - } frame_free(gspca_dev); } - file->private_data = NULL; module_put(gspca_dev->module); mutex_unlock(&gspca_dev->queue_lock); + mutex_unlock(&gspca_dev->usb_lock); PDEBUG(D_STREAM, "close done"); - return 0; + return v4l2_fh_release(file); } static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - struct gspca_dev *gspca_dev = priv; - int ret; + struct gspca_dev *gspca_dev = video_drvdata(file); - /* protect the access to the usb device */ - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - if (!gspca_dev->present) { - ret = -ENODEV; - goto out; - } strlcpy((char *) cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver); if (gspca_dev->dev->product != NULL) { @@ -1406,13 +1363,11 @@ static int vidioc_querycap(struct file *file, void *priv, } usb_make_path(gspca_dev->dev, (char *) cap->bus_info, sizeof(cap->bus_info)); - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE + cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - ret = 0; -out: - mutex_unlock(&gspca_dev->usb_lock); - return ret; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + return 0; } static int get_ctrl(struct gspca_dev *gspca_dev, @@ -1435,7 +1390,7 @@ static int get_ctrl(struct gspca_dev *gspca_dev, static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *q_ctrl) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); const struct ctrl *ctrls; struct gspca_ctrl *gspca_ctrl; int i, idx; @@ -1478,10 +1433,10 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); const struct ctrl *ctrls; struct gspca_ctrl *gspca_ctrl; - int idx, ret; + int idx; idx = get_ctrl(gspca_dev, ctrl->id); if (idx < 0) @@ -1501,74 +1456,52 @@ static int vidioc_s_ctrl(struct file *file, void *priv, return -ERANGE; } PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value); - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - if (!gspca_dev->present) { - ret = -ENODEV; - goto out; - } gspca_dev->usb_err = 0; - if (ctrls->set != NULL) { - ret = ctrls->set(gspca_dev, ctrl->value); - goto out; - } + if (ctrls->set != NULL) + return ctrls->set(gspca_dev, ctrl->value); if (gspca_ctrl != NULL) { gspca_ctrl->val = ctrl->value; if (ctrls->set_control != NULL && gspca_dev->streaming) ctrls->set_control(gspca_dev); } - ret = gspca_dev->usb_err; -out: - mutex_unlock(&gspca_dev->usb_lock); - return ret; + return gspca_dev->usb_err; } static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); const struct ctrl *ctrls; - int idx, ret; + int idx; idx = get_ctrl(gspca_dev, ctrl->id); if (idx < 0) return -EINVAL; ctrls = &gspca_dev->sd_desc->ctrls[idx]; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - if (!gspca_dev->present) { - ret = -ENODEV; - goto out; - } gspca_dev->usb_err = 0; - if (ctrls->get != NULL) { - ret = ctrls->get(gspca_dev, &ctrl->value); - goto out; - } + if (ctrls->get != NULL) + return ctrls->get(gspca_dev, &ctrl->value); if (gspca_dev->cam.ctrls != NULL) ctrl->value = gspca_dev->cam.ctrls[idx].val; - ret = 0; -out: - mutex_unlock(&gspca_dev->usb_lock); - return ret; + return 0; } static int vidioc_querymenu(struct file *file, void *priv, struct v4l2_querymenu *qmenu) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); if (!gspca_dev->sd_desc->querymenu) - return -EINVAL; + return -ENOTTY; return gspca_dev->sd_desc->querymenu(gspca_dev, qmenu); } static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *input) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); if (input->index != 0) return -EINVAL; @@ -1595,7 +1528,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) static int vidioc_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *rb) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); int i, ret = 0, streaming; i = rb->memory; /* (avoid compilation warning) */ @@ -1635,10 +1568,7 @@ static int vidioc_reqbufs(struct file *file, void *priv, /* stop streaming */ streaming = gspca_dev->streaming; if (streaming) { - mutex_lock(&gspca_dev->usb_lock); - gspca_dev->usb_err = 0; gspca_stream_off(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); /* Don't restart the stream when switching from read * to mmap mode */ @@ -1666,7 +1596,7 @@ out: static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *v4l2_buf) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); struct gspca_frame *frame; if (v4l2_buf->index < 0 @@ -1681,7 +1611,7 @@ static int vidioc_querybuf(struct file *file, void *priv, static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type buf_type) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); int ret; if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -1722,7 +1652,7 @@ out: static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type buf_type) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); int ret; if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) @@ -1743,13 +1673,7 @@ static int vidioc_streamoff(struct file *file, void *priv, } /* stop streaming */ - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) { - ret = -ERESTARTSYS; - goto out; - } - gspca_dev->usb_err = 0; gspca_stream_off(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); /* In case another thread is waiting in dqbuf */ wake_up_interruptible(&gspca_dev->wq); @@ -1766,71 +1690,44 @@ out: static int vidioc_g_jpegcomp(struct file *file, void *priv, struct v4l2_jpegcompression *jpegcomp) { - struct gspca_dev *gspca_dev = priv; - int ret; + struct gspca_dev *gspca_dev = video_drvdata(file); if (!gspca_dev->sd_desc->get_jcomp) - return -EINVAL; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; + return -ENOTTY; gspca_dev->usb_err = 0; - if (gspca_dev->present) - ret = gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - return ret; + return gspca_dev->sd_desc->get_jcomp(gspca_dev, jpegcomp); } static int vidioc_s_jpegcomp(struct file *file, void *priv, struct v4l2_jpegcompression *jpegcomp) { - struct gspca_dev *gspca_dev = priv; - int ret; + struct gspca_dev *gspca_dev = video_drvdata(file); if (!gspca_dev->sd_desc->set_jcomp) - return -EINVAL; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; + return -ENOTTY; gspca_dev->usb_err = 0; - if (gspca_dev->present) - ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); - else - ret = -ENODEV; - mutex_unlock(&gspca_dev->usb_lock); - return ret; + return gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); } static int vidioc_g_parm(struct file *filp, void *priv, struct v4l2_streamparm *parm) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(filp); parm->parm.capture.readbuffers = gspca_dev->nbufread; if (gspca_dev->sd_desc->get_streamparm) { - int ret; - - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - if (gspca_dev->present) { - gspca_dev->usb_err = 0; - gspca_dev->sd_desc->get_streamparm(gspca_dev, parm); - ret = gspca_dev->usb_err; - } else { - ret = -ENODEV; - } - mutex_unlock(&gspca_dev->usb_lock); - return ret; + gspca_dev->usb_err = 0; + gspca_dev->sd_desc->get_streamparm(gspca_dev, parm); + return gspca_dev->usb_err; } - return 0; } static int vidioc_s_parm(struct file *filp, void *priv, struct v4l2_streamparm *parm) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(filp); int n; n = parm->parm.capture.readbuffers; @@ -1840,19 +1737,9 @@ static int vidioc_s_parm(struct file *filp, void *priv, gspca_dev->nbufread = n; if (gspca_dev->sd_desc->set_streamparm) { - int ret; - - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; - if (gspca_dev->present) { - gspca_dev->usb_err = 0; - gspca_dev->sd_desc->set_streamparm(gspca_dev, parm); - ret = gspca_dev->usb_err; - } else { - ret = -ENODEV; - } - mutex_unlock(&gspca_dev->usb_lock); - return ret; + gspca_dev->usb_err = 0; + gspca_dev->sd_desc->set_streamparm(gspca_dev, parm); + return gspca_dev->usb_err; } return 0; @@ -1860,7 +1747,7 @@ static int vidioc_s_parm(struct file *filp, void *priv, static int dev_mmap(struct file *file, struct vm_area_struct *vma) { - struct gspca_dev *gspca_dev = file->private_data; + struct gspca_dev *gspca_dev = video_drvdata(file); struct gspca_frame *frame; struct page *page; unsigned long addr, start, size; @@ -1872,10 +1759,6 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma) if (mutex_lock_interruptible(&gspca_dev->queue_lock)) return -ERESTARTSYS; - if (!gspca_dev->present) { - ret = -ENODEV; - goto out; - } if (gspca_dev->capt_file != file) { ret = -EINVAL; goto out; @@ -1963,7 +1846,7 @@ static int frame_ready(struct gspca_dev *gspca_dev, struct file *file, static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *v4l2_buf) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); struct gspca_frame *frame; int i, j, ret; @@ -2003,14 +1886,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES; - if (gspca_dev->sd_desc->dq_callback) { - mutex_lock(&gspca_dev->usb_lock); - gspca_dev->usb_err = 0; - if (gspca_dev->present) - gspca_dev->sd_desc->dq_callback(gspca_dev); - mutex_unlock(&gspca_dev->usb_lock); - } - frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE; memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf); PDEBUG(D_FRAM, "dqbuf %d", j); @@ -2027,6 +1902,15 @@ static int vidioc_dqbuf(struct file *file, void *priv, } out: mutex_unlock(&gspca_dev->queue_lock); + + if (ret == 0 && gspca_dev->sd_desc->dq_callback) { + mutex_lock(&gspca_dev->usb_lock); + gspca_dev->usb_err = 0; + if (gspca_dev->present) + gspca_dev->sd_desc->dq_callback(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + } + return ret; } @@ -2039,7 +1923,7 @@ out: static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *v4l2_buf) { - struct gspca_dev *gspca_dev = priv; + struct gspca_dev *gspca_dev = video_drvdata(file); struct gspca_frame *frame; int i, index, ret; @@ -2098,6 +1982,10 @@ static int read_alloc(struct gspca_dev *gspca_dev, int i, ret; PDEBUG(D_STREAM, "read alloc"); + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + if (gspca_dev->nframes == 0) { struct v4l2_requestbuffers rb; @@ -2108,7 +1996,7 @@ static int read_alloc(struct gspca_dev *gspca_dev, ret = vidioc_reqbufs(file, gspca_dev, &rb); if (ret != 0) { PDEBUG(D_STREAM, "read reqbuf err %d", ret); - return ret; + goto out; } memset(&v4l2_buf, 0, sizeof v4l2_buf); v4l2_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; @@ -2118,61 +2006,69 @@ static int read_alloc(struct gspca_dev *gspca_dev, ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf); if (ret != 0) { PDEBUG(D_STREAM, "read qbuf err: %d", ret); - return ret; + goto out; } } - gspca_dev->memory = GSPCA_MEMORY_READ; } /* start streaming */ ret = vidioc_streamon(file, gspca_dev, V4L2_BUF_TYPE_VIDEO_CAPTURE); if (ret != 0) PDEBUG(D_STREAM, "read streamon err %d", ret); +out: + mutex_unlock(&gspca_dev->usb_lock); return ret; } static unsigned int dev_poll(struct file *file, poll_table *wait) { - struct gspca_dev *gspca_dev = file->private_data; - int ret; + struct gspca_dev *gspca_dev = video_drvdata(file); + unsigned long req_events = poll_requested_events(wait); + int ret = 0; PDEBUG(D_FRAM, "poll"); - poll_wait(file, &gspca_dev->wq, wait); + if (req_events & POLLPRI) + ret |= v4l2_ctrl_poll(file, wait); - /* if reqbufs is not done, the user would use read() */ - if (gspca_dev->memory == GSPCA_MEMORY_NO) { - ret = read_alloc(gspca_dev, file); - if (ret != 0) - return POLLERR; - } + if (req_events & (POLLIN | POLLRDNORM)) { + /* if reqbufs is not done, the user would use read() */ + if (gspca_dev->memory == GSPCA_MEMORY_NO) { + if (read_alloc(gspca_dev, file) != 0) { + ret |= POLLERR; + goto out; + } + } - if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) - return POLLERR; + poll_wait(file, &gspca_dev->wq, wait); - /* check if an image has been received */ - if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i)) - ret = POLLIN | POLLRDNORM; /* yes */ - else - ret = 0; - mutex_unlock(&gspca_dev->queue_lock); + /* check if an image has been received */ + if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0) { + ret |= POLLERR; + goto out; + } + if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i)) + ret |= POLLIN | POLLRDNORM; + mutex_unlock(&gspca_dev->queue_lock); + } + +out: if (!gspca_dev->present) - return POLLHUP; + ret |= POLLHUP; + return ret; } static ssize_t dev_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { - struct gspca_dev *gspca_dev = file->private_data; + struct gspca_dev *gspca_dev = video_drvdata(file); struct gspca_frame *frame; struct v4l2_buffer v4l2_buf; struct timeval timestamp; int n, ret, ret2; PDEBUG(D_FRAM, "read (%zd)", count); - if (!gspca_dev->present) - return -ENODEV; if (gspca_dev->memory == GSPCA_MEMORY_NO) { /* first time ? */ ret = read_alloc(gspca_dev, file); if (ret != 0) @@ -2266,13 +2162,15 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_s_register = vidioc_s_register, #endif .vidioc_g_chip_ident = vidioc_g_chip_ident, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static const struct video_device gspca_template = { .name = "gspca main driver", .fops = &dev_fops, .ioctl_ops = &dev_ioctl_ops, - .release = gspca_release, + .release = video_device_release_empty, /* We use v4l2_dev.release */ }; /* initialize the controls */ @@ -2344,9 +2242,24 @@ int gspca_dev_probe2(struct usb_interface *intf, } } + gspca_dev->v4l2_dev.release = gspca_release; + ret = v4l2_device_register(&intf->dev, &gspca_dev->v4l2_dev); + if (ret) + goto out; gspca_dev->sd_desc = sd_desc; gspca_dev->nbufread = 2; gspca_dev->empty_packet = -1; /* don't check the empty packets */ + gspca_dev->vdev = gspca_template; + gspca_dev->vdev.v4l2_dev = &gspca_dev->v4l2_dev; + video_set_drvdata(&gspca_dev->vdev, gspca_dev); + set_bit(V4L2_FL_USE_FH_PRIO, &gspca_dev->vdev.flags); + gspca_dev->module = module; + gspca_dev->present = 1; + + mutex_init(&gspca_dev->usb_lock); + gspca_dev->vdev.lock = &gspca_dev->usb_lock; + mutex_init(&gspca_dev->queue_lock); + init_waitqueue_head(&gspca_dev->wq); /* configure the subdriver and initialize the USB device */ ret = sd_desc->config(gspca_dev, id); @@ -2357,21 +2270,26 @@ int gspca_dev_probe2(struct usb_interface *intf, ret = sd_desc->init(gspca_dev); if (ret < 0) goto out; + if (sd_desc->init_controls) + ret = sd_desc->init_controls(gspca_dev); + if (ret < 0) + goto out; gspca_set_default_mode(gspca_dev); ret = gspca_input_connect(gspca_dev); if (ret) goto out; - mutex_init(&gspca_dev->usb_lock); - mutex_init(&gspca_dev->queue_lock); - init_waitqueue_head(&gspca_dev->wq); + /* + * Don't take usb_lock for these ioctls. This improves latency if + * usb_lock is taken for a long time, e.g. when changing a control + * value, and a new frame is ready to be dequeued. + */ + v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_DQBUF); + v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QBUF); + v4l2_disable_ioctl_locking(&gspca_dev->vdev, VIDIOC_QUERYBUF); /* init video stuff */ - memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template); - gspca_dev->vdev.parent = &intf->dev; - gspca_dev->module = module; - gspca_dev->present = 1; ret = video_register_device(&gspca_dev->vdev, VFL_TYPE_GRABBER, -1); @@ -2391,6 +2309,7 @@ out: if (gspca_dev->input_dev) input_unregister_device(gspca_dev->input_dev); #endif + v4l2_ctrl_handler_free(gspca_dev->vdev.ctrl_handler); kfree(gspca_dev->usb_buf); kfree(gspca_dev); return ret; @@ -2437,11 +2356,12 @@ void gspca_disconnect(struct usb_interface *intf) PDEBUG(D_PROBE, "%s disconnect", video_device_node_name(&gspca_dev->vdev)); + mutex_lock(&gspca_dev->usb_lock); + usb_set_intfdata(intf, NULL); + gspca_dev->dev = NULL; gspca_dev->present = 0; - wake_up_interruptible(&gspca_dev->wq); - destroy_urbs(gspca_dev); #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) @@ -2452,18 +2372,19 @@ void gspca_disconnect(struct usb_interface *intf) input_unregister_device(input_dev); } #endif + /* Free subdriver's streaming resources / stop sd workqueue(s) */ + if (gspca_dev->sd_desc->stop0 && gspca_dev->streaming) + gspca_dev->sd_desc->stop0(gspca_dev); + gspca_dev->streaming = 0; + wake_up_interruptible(&gspca_dev->wq); - /* the device is freed at exit of this function */ - gspca_dev->dev = NULL; - mutex_unlock(&gspca_dev->usb_lock); + v4l2_device_disconnect(&gspca_dev->v4l2_dev); + video_unregister_device(&gspca_dev->vdev); - usb_set_intfdata(intf, NULL); + mutex_unlock(&gspca_dev->usb_lock); - /* release the device */ /* (this will call gspca_release() immediately or on last close) */ - video_unregister_device(&gspca_dev->vdev); - -/* PDEBUG(D_PROBE, "disconnect complete"); */ + v4l2_device_put(&gspca_dev->v4l2_dev); } EXPORT_SYMBOL(gspca_disconnect); @@ -2474,7 +2395,9 @@ int gspca_suspend(struct usb_interface *intf, pm_message_t message) if (!gspca_dev->streaming) return 0; + mutex_lock(&gspca_dev->usb_lock); gspca_dev->frozen = 1; /* avoid urb error messages */ + gspca_dev->usb_err = 0; if (gspca_dev->sd_desc->stopN) gspca_dev->sd_desc->stopN(gspca_dev); destroy_urbs(gspca_dev); @@ -2482,6 +2405,7 @@ int gspca_suspend(struct usb_interface *intf, pm_message_t message) gspca_set_alt0(gspca_dev); if (gspca_dev->sd_desc->stop0) gspca_dev->sd_desc->stop0(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); return 0; } EXPORT_SYMBOL(gspca_suspend); @@ -2489,105 +2413,28 @@ EXPORT_SYMBOL(gspca_suspend); int gspca_resume(struct usb_interface *intf) { struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + int streaming, ret = 0; + mutex_lock(&gspca_dev->usb_lock); gspca_dev->frozen = 0; + gspca_dev->usb_err = 0; gspca_dev->sd_desc->init(gspca_dev); gspca_input_create_urb(gspca_dev); - if (gspca_dev->streaming) - return gspca_init_transfer(gspca_dev); - return 0; + /* + * Most subdrivers send all ctrl values on sd_start and thus + * only write to the device registers on s_ctrl when streaming -> + * Clear streaming to avoid setting all ctrls twice. + */ + streaming = gspca_dev->streaming; + gspca_dev->streaming = 0; + v4l2_ctrl_handler_setup(gspca_dev->vdev.ctrl_handler); + if (streaming) + ret = gspca_init_transfer(gspca_dev); + mutex_unlock(&gspca_dev->usb_lock); + return ret; } EXPORT_SYMBOL(gspca_resume); #endif -/* -- cam driver utility functions -- */ - -/* auto gain and exposure algorithm based on the knee algorithm described here: - http://ytse.tricolour.net/docs/LowLightOptimization.html - - Returns 0 if no changes were made, 1 if the gain and or exposure settings - where changed. */ -int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, - int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee) -{ - int i, steps, gain, orig_gain, exposure, orig_exposure, autogain; - const struct ctrl *gain_ctrl = NULL; - const struct ctrl *exposure_ctrl = NULL; - const struct ctrl *autogain_ctrl = NULL; - int retval = 0; - - for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) { - if (gspca_dev->ctrl_dis & (1 << i)) - continue; - if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_GAIN) - gain_ctrl = &gspca_dev->sd_desc->ctrls[i]; - if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_EXPOSURE) - exposure_ctrl = &gspca_dev->sd_desc->ctrls[i]; - if (gspca_dev->sd_desc->ctrls[i].qctrl.id == V4L2_CID_AUTOGAIN) - autogain_ctrl = &gspca_dev->sd_desc->ctrls[i]; - } - if (!gain_ctrl || !exposure_ctrl || !autogain_ctrl) { - PDEBUG(D_ERR, "Error: gspca_auto_gain_n_exposure called " - "on cam without (auto)gain/exposure"); - return 0; - } - - if (gain_ctrl->get(gspca_dev, &gain) || - exposure_ctrl->get(gspca_dev, &exposure) || - autogain_ctrl->get(gspca_dev, &autogain) || !autogain) - return 0; - - orig_gain = gain; - orig_exposure = exposure; - - /* If we are of a multiple of deadzone, do multiple steps to reach the - desired lumination fast (with the risc of a slight overshoot) */ - steps = abs(desired_avg_lum - avg_lum) / deadzone; - - PDEBUG(D_FRAM, "autogain: lum: %d, desired: %d, steps: %d", - avg_lum, desired_avg_lum, steps); - - for (i = 0; i < steps; i++) { - if (avg_lum > desired_avg_lum) { - if (gain > gain_knee) - gain--; - else if (exposure > exposure_knee) - exposure--; - else if (gain > gain_ctrl->qctrl.default_value) - gain--; - else if (exposure > exposure_ctrl->qctrl.minimum) - exposure--; - else if (gain > gain_ctrl->qctrl.minimum) - gain--; - else - break; - } else { - if (gain < gain_ctrl->qctrl.default_value) - gain++; - else if (exposure < exposure_knee) - exposure++; - else if (gain < gain_knee) - gain++; - else if (exposure < exposure_ctrl->qctrl.maximum) - exposure++; - else if (gain < gain_ctrl->qctrl.maximum) - gain++; - else - break; - } - } - - if (gain != orig_gain) { - gain_ctrl->set(gspca_dev, gain); - retval = 1; - } - if (exposure != orig_exposure) { - exposure_ctrl->set(gspca_dev, exposure); - retval = 1; - } - - return retval; -} -EXPORT_SYMBOL(gspca_auto_gain_n_exposure); /* -- module insert / remove -- */ static int __init gspca_init(void) diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h index 589009f4496..dc688c7f5e4 100644 --- a/drivers/media/video/gspca/gspca.h +++ b/drivers/media/video/gspca/gspca.h @@ -6,6 +6,8 @@ #include <linux/usb.h> #include <linux/videodev2.h> #include <media/v4l2-common.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> #include <linux/mutex.h> /* compilation option */ @@ -115,6 +117,7 @@ struct sd_desc { /* mandatory operations */ cam_cf_op config; /* called on probe */ cam_op init; /* called on probe and resume */ + cam_op init_controls; /* called on probe */ cam_op start; /* called on stream on after URBs creation */ cam_pkt_op pkt_scan; /* optional operations */ @@ -158,8 +161,10 @@ struct gspca_frame { struct gspca_dev { struct video_device vdev; /* !! must be the first item */ struct module *module; /* subdriver handling the device */ + struct v4l2_device v4l2_dev; struct usb_device *dev; struct file *capt_file; /* file doing video capture */ + /* protected by queue_lock */ #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) struct input_dev *input_dev; char phys[64]; /* physical device path */ @@ -169,6 +174,16 @@ struct gspca_dev { const struct sd_desc *sd_desc; /* subdriver description */ unsigned ctrl_dis; /* disabled controls (bit map) */ unsigned ctrl_inac; /* inactive controls (bit map) */ + struct v4l2_ctrl_handler ctrl_handler; + + /* autogain and exposure or gain control cluster, these are global as + the autogain/exposure functions in autogain_functions.c use them */ + struct { + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; + int exp_too_low_cnt, exp_too_high_cnt; + }; #define USB_BUF_SZ 64 __u8 *usb_buf; /* buffer for USB exchanges */ @@ -189,7 +204,7 @@ struct gspca_dev { u8 fr_o; /* next frame to dequeue */ __u8 last_packet_type; __s8 empty_packet; /* if (-1) don't check empty packets */ - __u8 streaming; + __u8 streaming; /* protected by both mutexes (*) */ __u8 curr_mode; /* current camera mode */ __u32 pixfmt; /* current mode parameters */ @@ -211,6 +226,10 @@ struct gspca_dev { __u8 iface; /* USB interface number */ __u8 alt; /* USB alternate setting */ u8 audio; /* presence of audio device */ + + /* (*) These variables are proteced by both usb_lock and queue_lock, + that is any code setting them is holding *both*, which means that + any code getting them needs to hold at least one of them */ }; int gspca_dev_probe(struct usb_interface *intf, @@ -232,6 +251,9 @@ void gspca_frame_add(struct gspca_dev *gspca_dev, int gspca_suspend(struct usb_interface *intf, pm_message_t message); int gspca_resume(struct usb_interface *intf); #endif -int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum, +int gspca_expo_autogain(struct gspca_dev *gspca_dev, int avg_lum, int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee); +int gspca_coarse_grained_expo_autogain(struct gspca_dev *gspca_dev, + int avg_lum, int desired_avg_lum, int deadzone); + #endif /* GSPCAV2_H */ diff --git a/drivers/media/video/gspca/jl2005bcd.c b/drivers/media/video/gspca/jl2005bcd.c index 53f58ef367c..9c591c7c6f5 100644 --- a/drivers/media/video/gspca/jl2005bcd.c +++ b/drivers/media/video/gspca/jl2005bcd.c @@ -335,7 +335,11 @@ static void jl2005c_dostream(struct work_struct *work) goto quit_stream; } - while (gspca_dev->present && gspca_dev->streaming) { + while (gspca_dev->dev && gspca_dev->streaming) { +#ifdef CONFIG_PM + if (gspca_dev->frozen) + break; +#endif /* Check if this is a new frame. If so, start the frame first */ if (!header_read) { mutex_lock(&gspca_dev->usb_lock); @@ -367,7 +371,7 @@ static void jl2005c_dostream(struct work_struct *work) buffer, act_len); header_read = 1; } - while (bytes_left > 0 && gspca_dev->present) { + while (bytes_left > 0 && gspca_dev->dev) { data_len = bytes_left > JL2005C_MAX_TRANSFER ? JL2005C_MAX_TRANSFER : bytes_left; ret = usb_bulk_msg(gspca_dev->dev, @@ -390,7 +394,7 @@ static void jl2005c_dostream(struct work_struct *work) } } quit_stream: - if (gspca_dev->present) { + if (gspca_dev->dev) { mutex_lock(&gspca_dev->usb_lock); jl2005c_stop(gspca_dev); mutex_unlock(&gspca_dev->usb_lock); diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c index b0231465afa..ec7b21ee79f 100644 --- a/drivers/media/video/gspca/mars.c +++ b/drivers/media/video/gspca/mars.c @@ -30,22 +30,19 @@ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>"); MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver"); MODULE_LICENSE("GPL"); -/* controls */ -enum e_ctrl { - BRIGHTNESS, - COLORS, - GAMMA, - SHARPNESS, - ILLUM_TOP, - ILLUM_BOT, - NCTRLS /* number of controls */ -}; - /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - struct gspca_ctrl ctrls[NCTRLS]; + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *saturation; + struct v4l2_ctrl *sharpness; + struct v4l2_ctrl *gamma; + struct { /* illuminator control cluster */ + struct v4l2_ctrl *illum_top; + struct v4l2_ctrl *illum_bottom; + }; + struct v4l2_ctrl *jpegqual; u8 quality; #define QUALITY_MIN 40 @@ -56,89 +53,10 @@ struct sd { }; /* V4L2 controls supported by the driver */ -static void setbrightness(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); -static void setgamma(struct gspca_dev *gspca_dev); -static void setsharpness(struct gspca_dev *gspca_dev); -static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val); -static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 30, - .step = 1, - .default_value = 15, - }, - .set_control = setbrightness - }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Color", - .minimum = 1, - .maximum = 255, - .step = 1, - .default_value = 200, - }, - .set_control = setcolors - }, -[GAMMA] = { - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 1, - }, - .set_control = setgamma - }, -[SHARPNESS] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 2, - .step = 1, - .default_value = 1, - }, - .set_control = setsharpness - }, -[ILLUM_TOP] = { - { - .id = V4L2_CID_ILLUMINATORS_1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Top illuminator", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = V4L2_CTRL_FLAG_UPDATE, - }, - .set = sd_setilluminator1 - }, -[ILLUM_BOT] = { - { - .id = V4L2_CID_ILLUMINATORS_2, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Bottom illuminator", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - .flags = V4L2_CTRL_FLAG_UPDATE, - }, - .set = sd_setilluminator2 - }, -}; +static void setbrightness(struct gspca_dev *gspca_dev, s32 val); +static void setcolors(struct gspca_dev *gspca_dev, s32 val); +static void setgamma(struct gspca_dev *gspca_dev, s32 val); +static void setsharpness(struct gspca_dev *gspca_dev, s32 val); static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, @@ -198,59 +116,130 @@ static void mi_w(struct gspca_dev *gspca_dev, reg_w(gspca_dev, 4); } -static void setbrightness(struct gspca_dev *gspca_dev) +static void setbrightness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - gspca_dev->usb_buf[0] = 0x61; - gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val; + gspca_dev->usb_buf[1] = val; reg_w(gspca_dev, 2); } -static void setcolors(struct gspca_dev *gspca_dev) +static void setcolors(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - s16 val; - - val = sd->ctrls[COLORS].val; gspca_dev->usb_buf[0] = 0x5f; gspca_dev->usb_buf[1] = val << 3; gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04; reg_w(gspca_dev, 3); } -static void setgamma(struct gspca_dev *gspca_dev) +static void setgamma(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - gspca_dev->usb_buf[0] = 0x06; - gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40; + gspca_dev->usb_buf[1] = val * 0x40; reg_w(gspca_dev, 2); } -static void setsharpness(struct gspca_dev *gspca_dev) +static void setsharpness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - gspca_dev->usb_buf[0] = 0x67; - gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3; + gspca_dev->usb_buf[1] = val * 4 + 3; reg_w(gspca_dev, 2); } -static void setilluminators(struct gspca_dev *gspca_dev) +static void setilluminators(struct gspca_dev *gspca_dev, bool top, bool bottom) { - struct sd *sd = (struct sd *) gspca_dev; - + /* both are off if not streaming */ gspca_dev->usb_buf[0] = 0x22; - if (sd->ctrls[ILLUM_TOP].val) + if (top) gspca_dev->usb_buf[1] = 0x76; - else if (sd->ctrls[ILLUM_BOT].val) + else if (bottom) gspca_dev->usb_buf[1] = 0x7a; else gspca_dev->usb_buf[1] = 0x7e; reg_w(gspca_dev, 2); } +static int mars_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (ctrl->id == V4L2_CID_ILLUMINATORS_1) { + /* only one can be on at a time */ + if (ctrl->is_new && ctrl->val) + sd->illum_bottom->val = 0; + if (sd->illum_bottom->is_new && sd->illum_bottom->val) + sd->illum_top->val = 0; + } + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setbrightness(gspca_dev, ctrl->val); + break; + case V4L2_CID_SATURATION: + setcolors(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAMMA: + setgamma(gspca_dev, ctrl->val); + break; + case V4L2_CID_ILLUMINATORS_1: + setilluminators(gspca_dev, sd->illum_top->val, + sd->illum_bottom->val); + break; + case V4L2_CID_SHARPNESS: + setsharpness(gspca_dev, ctrl->val); + break; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + jpeg_set_qual(sd->jpeg_hdr, ctrl->val); + break; + default: + return -EINVAL; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops mars_ctrl_ops = { + .s_ctrl = mars_s_ctrl, +}; + +/* this function is called at probe time */ +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 7); + sd->brightness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 30, 1, 15); + sd->saturation = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 200); + sd->gamma = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_GAMMA, 0, 3, 1, 1); + sd->sharpness = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 2, 1, 1); + sd->illum_top = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 0); + sd->illum_top->flags |= V4L2_CTRL_FLAG_UPDATE; + sd->illum_bottom = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 0); + sd->illum_bottom->flags |= V4L2_CTRL_FLAG_UPDATE; + sd->jpegqual = v4l2_ctrl_new_std(hdl, &mars_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, + QUALITY_MIN, QUALITY_MAX, 1, QUALITY_DEF); + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + v4l2_ctrl_cluster(2, &sd->illum_top); + return 0; +} + /* this function is called at probe time */ static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) @@ -261,7 +250,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); - cam->ctrls = sd->ctrls; sd->quality = QUALITY_DEF; return 0; } @@ -269,7 +257,6 @@ static int sd_config(struct gspca_dev *gspca_dev, /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { - gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT); return 0; } @@ -282,7 +269,7 @@ static int sd_start(struct gspca_dev *gspca_dev) /* create the JPEG header */ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width, 0x21); /* JPEG 422 */ - jpeg_set_qual(sd->jpeg_hdr, sd->quality); + jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual)); data = gspca_dev->usb_buf; @@ -301,7 +288,7 @@ static int sd_start(struct gspca_dev *gspca_dev) data[5] = 0x30; /* reg 4, MI, PAS5101 : * 0x30 for 24mhz , 0x28 for 12mhz */ data[6] = 0x02; /* reg 5, H start - was 0x04 */ - data[7] = sd->ctrls[GAMMA].val * 0x40; /* reg 0x06: gamma */ + data[7] = v4l2_ctrl_g_ctrl(sd->gamma) * 0x40; /* reg 0x06: gamma */ data[8] = 0x01; /* reg 7, V start - was 0x03 */ /* if (h_size == 320 ) */ /* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */ @@ -333,16 +320,16 @@ static int sd_start(struct gspca_dev *gspca_dev) /* reg 0x5f/0x60 (LE) = saturation */ /* h (60): xxxx x100 * l (5f): xxxx x000 */ - data[2] = sd->ctrls[COLORS].val << 3; - data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04; - data[4] = sd->ctrls[BRIGHTNESS].val; /* reg 0x61 = brightness */ + data[2] = v4l2_ctrl_g_ctrl(sd->saturation) << 3; + data[3] = ((v4l2_ctrl_g_ctrl(sd->saturation) >> 2) & 0xf8) | 0x04; + data[4] = v4l2_ctrl_g_ctrl(sd->brightness); /* reg 0x61 = brightness */ data[5] = 0x00; reg_w(gspca_dev, 6); data[0] = 0x67; /*jfm: from win trace*/ - data[1] = sd->ctrls[SHARPNESS].val * 4 + 3; + data[1] = v4l2_ctrl_g_ctrl(sd->sharpness) * 4 + 3; data[2] = 0x14; reg_w(gspca_dev, 3); @@ -365,7 +352,9 @@ static int sd_start(struct gspca_dev *gspca_dev) data[1] = 0x4d; /* ISOC transferring enable... */ reg_w(gspca_dev, 2); - gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */ + setilluminators(gspca_dev, v4l2_ctrl_g_ctrl(sd->illum_top), + v4l2_ctrl_g_ctrl(sd->illum_bottom)); + return gspca_dev->usb_err; } @@ -373,11 +362,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT); - if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) { - sd->ctrls[ILLUM_TOP].val = 0; - sd->ctrls[ILLUM_BOT].val = 0; - setilluminators(gspca_dev); + if (v4l2_ctrl_g_ctrl(sd->illum_top) || + v4l2_ctrl_g_ctrl(sd->illum_bottom)) { + setilluminators(gspca_dev, false, false); msleep(20); } @@ -424,43 +411,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* only one illuminator may be on */ - sd->ctrls[ILLUM_TOP].val = val; - if (val) - sd->ctrls[ILLUM_BOT].val = 0; - setilluminators(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - /* only one illuminator may be on */ - sd->ctrls[ILLUM_BOT].val = val; - if (val) - sd->ctrls[ILLUM_TOP].val = 0; - setilluminators(gspca_dev); - return gspca_dev->usb_err; -} - static int sd_set_jcomp(struct gspca_dev *gspca_dev, struct v4l2_jpegcompression *jcomp) { struct sd *sd = (struct sd *) gspca_dev; + int ret; - if (jcomp->quality < QUALITY_MIN) - sd->quality = QUALITY_MIN; - else if (jcomp->quality > QUALITY_MAX) - sd->quality = QUALITY_MAX; - else - sd->quality = jcomp->quality; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->quality); + ret = v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality); + if (ret) + return ret; + jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual); return 0; } @@ -470,7 +430,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->quality; + jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual); jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT; return 0; @@ -479,10 +439,9 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev, /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = NCTRLS, .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, @@ -513,6 +472,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c index 7167cac7359..42e021931e6 100644 --- a/drivers/media/video/gspca/nw80x.c +++ b/drivers/media/video/gspca/nw80x.c @@ -2001,6 +2001,8 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) return gspca_dev->usb_err; } +#define WANT_REGULAR_AUTOGAIN +#define WANT_COARSE_EXPO_AUTOGAIN #include "autogain_functions.h" static void do_autogain(struct gspca_dev *gspca_dev) diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c index 739e8a2a2d3..183457c5cfd 100644 --- a/drivers/media/video/gspca/ov519.c +++ b/drivers/media/video/gspca/ov519.c @@ -2804,7 +2804,7 @@ static void ov7xx0_configure(struct sd *sd) /* add OV7670 here * it appears to be wrongly detected as a 7610 by default */ if (rc < 0) { - PDEBUG(D_ERR, "Error detecting sensor type"); + pr_err("Error detecting sensor type\n"); return; } if ((rc & 3) == 3) { @@ -2832,12 +2832,12 @@ static void ov7xx0_configure(struct sd *sd) /* try to read product id registers */ high = i2c_r(sd, 0x0a); if (high < 0) { - PDEBUG(D_ERR, "Error detecting camera chip PID"); + pr_err("Error detecting camera chip PID\n"); return; } low = i2c_r(sd, 0x0b); if (low < 0) { - PDEBUG(D_ERR, "Error detecting camera chip VER"); + pr_err("Error detecting camera chip VER\n"); return; } if (high == 0x76) { @@ -2863,7 +2863,7 @@ static void ov7xx0_configure(struct sd *sd) sd->sensor = SEN_OV7660; break; default: - PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low); + pr_err("Unknown sensor: 0x76%02x\n", low); return; } } else { @@ -2884,7 +2884,7 @@ static void ov6xx0_configure(struct sd *sd) /* Detect sensor (sub)type */ rc = i2c_r(sd, OV7610_REG_COM_I); if (rc < 0) { - PDEBUG(D_ERR, "Error detecting sensor type"); + pr_err("Error detecting sensor type\n"); return; } diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c index 04753391de3..b5acb1e4b4e 100644 --- a/drivers/media/video/gspca/ov534.c +++ b/drivers/media/video/gspca/ov534.c @@ -34,6 +34,8 @@ #include "gspca.h" +#include <linux/fixp-arith.h> + #define OV534_REG_ADDRESS 0xf1 /* sensor address */ #define OV534_REG_SUBADDR 0xf2 #define OV534_REG_WRITE 0xf3 @@ -53,6 +55,8 @@ MODULE_LICENSE("GPL"); /* controls */ enum e_ctrl { + HUE, + SATURATION, BRIGHTNESS, CONTRAST, GAIN, @@ -63,7 +67,6 @@ enum e_ctrl { SHARPNESS, HFLIP, VFLIP, - COLORS, LIGHTFREQ, NCTRLS /* number of controls */ }; @@ -87,6 +90,8 @@ enum sensors { }; /* V4L2 controls supported by the driver */ +static void sethue(struct gspca_dev *gspca_dev); +static void setsaturation(struct gspca_dev *gspca_dev); static void setbrightness(struct gspca_dev *gspca_dev); static void setcontrast(struct gspca_dev *gspca_dev); static void setgain(struct gspca_dev *gspca_dev); @@ -96,13 +101,36 @@ static void setawb(struct gspca_dev *gspca_dev); static void setaec(struct gspca_dev *gspca_dev); static void setsharpness(struct gspca_dev *gspca_dev); static void sethvflip(struct gspca_dev *gspca_dev); -static void setcolors(struct gspca_dev *gspca_dev); static void setlightfreq(struct gspca_dev *gspca_dev); static int sd_start(struct gspca_dev *gspca_dev); static void sd_stopN(struct gspca_dev *gspca_dev); static const struct ctrl sd_ctrls[] = { +[HUE] = { + { + .id = V4L2_CID_HUE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Hue", + .minimum = -90, + .maximum = 90, + .step = 1, + .default_value = 0, + }, + .set_control = sethue + }, +[SATURATION] = { + { + .id = V4L2_CID_SATURATION, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Saturation", + .minimum = 0, + .maximum = 255, + .step = 1, + .default_value = 64, + }, + .set_control = setsaturation + }, [BRIGHTNESS] = { { .id = V4L2_CID_BRIGHTNESS, @@ -223,18 +251,6 @@ static const struct ctrl sd_ctrls[] = { }, .set_control = sethvflip }, -[COLORS] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 6, - .step = 1, - .default_value = 3, - }, - .set_control = setcolors - }, [LIGHTFREQ] = { { .id = V4L2_CID_POWER_LINE_FREQUENCY, @@ -684,7 +700,7 @@ static const u8 sensor_init_772x[][2] = { { 0x9c, 0x20 }, { 0x9e, 0x81 }, - { 0xa6, 0x04 }, + { 0xa6, 0x07 }, { 0x7e, 0x0c }, { 0x7f, 0x16 }, { 0x80, 0x2a }, @@ -955,6 +971,74 @@ static void set_frame_rate(struct gspca_dev *gspca_dev) PDEBUG(D_PROBE, "frame_rate: %d", r->fps); } +static void sethue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; + + val = sd->ctrls[HUE].val; + if (sd->sensor == SENSOR_OV767x) { + /* TBD */ + } else { + s16 huesin; + s16 huecos; + + /* fixp_sin and fixp_cos accept only positive values, while + * our val is between -90 and 90 + */ + val += 360; + + /* According to the datasheet the registers expect HUESIN and + * HUECOS to be the result of the trigonometric functions, + * scaled by 0x80. + * + * The 0x100 here represents the maximun absolute value + * returned byt fixp_sin and fixp_cos, so the scaling will + * consider the result like in the interval [-1.0, 1.0]. + */ + huesin = fixp_sin(val) * 0x80 / 0x100; + huecos = fixp_cos(val) * 0x80 / 0x100; + + if (huesin < 0) { + sccb_reg_write(gspca_dev, 0xab, + sccb_reg_read(gspca_dev, 0xab) | 0x2); + huesin = -huesin; + } else { + sccb_reg_write(gspca_dev, 0xab, + sccb_reg_read(gspca_dev, 0xab) & ~0x2); + + } + sccb_reg_write(gspca_dev, 0xa9, (u8)huecos); + sccb_reg_write(gspca_dev, 0xaa, (u8)huesin); + } +} + +static void setsaturation(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int val; + + val = sd->ctrls[SATURATION].val; + if (sd->sensor == SENSOR_OV767x) { + int i; + static u8 color_tb[][6] = { + {0x42, 0x42, 0x00, 0x11, 0x30, 0x41}, + {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52}, + {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66}, + {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80}, + {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a}, + {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8}, + {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd}, + }; + + for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++) + sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]); + } else { + sccb_reg_write(gspca_dev, 0xa7, val); /* U saturation */ + sccb_reg_write(gspca_dev, 0xa8, val); /* V saturation */ + } +} + static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -1132,26 +1216,6 @@ static void sethvflip(struct gspca_dev *gspca_dev) } } -static void setcolors(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - u8 val; - int i; - static u8 color_tb[][6] = { - {0x42, 0x42, 0x00, 0x11, 0x30, 0x41}, - {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52}, - {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66}, - {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80}, - {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a}, - {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8}, - {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd}, - }; - - val = sd->ctrls[COLORS].val; - for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++) - sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]); -} - static void setlightfreq(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -1225,9 +1289,13 @@ static int sd_init(struct gspca_dev *gspca_dev) if ((sensor_id & 0xfff0) == 0x7670) { sd->sensor = SENSOR_OV767x; - gspca_dev->ctrl_dis = (1 << GAIN) | + gspca_dev->ctrl_dis = (1 << HUE) | + (1 << GAIN) | (1 << AGC) | (1 << SHARPNESS); /* auto */ + sd->ctrls[SATURATION].min = 0, + sd->ctrls[SATURATION].max = 6, + sd->ctrls[SATURATION].def = 3, sd->ctrls[BRIGHTNESS].min = -127; sd->ctrls[BRIGHTNESS].max = 127; sd->ctrls[BRIGHTNESS].def = 0; @@ -1243,7 +1311,6 @@ static int sd_init(struct gspca_dev *gspca_dev) gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode); } else { sd->sensor = SENSOR_OV772x; - gspca_dev->ctrl_dis = (1 << COLORS); gspca_dev->cam.bulk = 1; gspca_dev->cam.bulk_size = 16384; gspca_dev->cam.bulk_nurbs = 2; @@ -1302,6 +1369,9 @@ static int sd_start(struct gspca_dev *gspca_dev) set_frame_rate(gspca_dev); + if (!(gspca_dev->ctrl_dis & (1 << HUE))) + sethue(gspca_dev); + setsaturation(gspca_dev); if (!(gspca_dev->ctrl_dis & (1 << AGC))) setagc(gspca_dev); setawb(gspca_dev); @@ -1314,8 +1384,6 @@ static int sd_start(struct gspca_dev *gspca_dev) if (!(gspca_dev->ctrl_dis & (1 << SHARPNESS))) setsharpness(gspca_dev); sethvflip(gspca_dev); - if (!(gspca_dev->ctrl_dis & (1 << COLORS))) - setcolors(gspca_dev); setlightfreq(gspca_dev); ov534_set_led(gspca_dev, 1); diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c index 3844c49f269..fa661c6d6d5 100644 --- a/drivers/media/video/gspca/pac207.c +++ b/drivers/media/video/gspca/pac207.c @@ -29,6 +29,8 @@ #include <linux/input.h> #include "gspca.h" +/* Include pac common sof detection functions */ +#include "pac_common.h" MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_DESCRIPTION("Pixart PAC207"); @@ -39,16 +41,17 @@ MODULE_LICENSE("GPL"); #define PAC207_BRIGHTNESS_MIN 0 #define PAC207_BRIGHTNESS_MAX 255 #define PAC207_BRIGHTNESS_DEFAULT 46 +#define PAC207_BRIGHTNESS_REG 0x08 #define PAC207_EXPOSURE_MIN 3 #define PAC207_EXPOSURE_MAX 90 /* 1 sec expo time / 1 fps */ #define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */ -#define PAC207_EXPOSURE_KNEE 9 /* fps: 90 / exposure -> 9: 10 fps */ +#define PAC207_EXPOSURE_REG 0x02 #define PAC207_GAIN_MIN 0 #define PAC207_GAIN_MAX 31 #define PAC207_GAIN_DEFAULT 7 /* power on default: 9 */ -#define PAC207_GAIN_KNEE 15 +#define PAC207_GAIN_REG 0x0e #define PAC207_AUTOGAIN_DEADZONE 30 @@ -56,13 +59,9 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - u8 mode; - - u8 brightness; - u8 exposure; - u8 autogain; - u8 gain; + struct v4l2_ctrl *brightness; + u8 mode; u8 sof_read; u8 header_read; u8 autogain_ignore_frames; @@ -70,80 +69,6 @@ struct sd { atomic_t avg_lum; }; -/* V4L2 controls supported by the driver */ -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); - -static const struct ctrl sd_ctrls[] = { -#define SD_BRIGHTNESS 0 - { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = PAC207_BRIGHTNESS_MIN, - .maximum = PAC207_BRIGHTNESS_MAX, - .step = 1, - .default_value = PAC207_BRIGHTNESS_DEFAULT, - .flags = 0, - }, - .set = sd_setbrightness, - .get = sd_getbrightness, - }, -#define SD_EXPOSURE 1 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = PAC207_EXPOSURE_MIN, - .maximum = PAC207_EXPOSURE_MAX, - .step = 1, - .default_value = PAC207_EXPOSURE_DEFAULT, - .flags = 0, - }, - .set = sd_setexposure, - .get = sd_getexposure, - }, -#define SD_AUTOGAIN 2 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - .flags = 0, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, -#define SD_GAIN 3 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = PAC207_GAIN_MIN, - .maximum = PAC207_GAIN_MAX, - .step = 1, - .default_value = PAC207_GAIN_DEFAULT, - .flags = 0, - }, - .set = sd_setgain, - .get = sd_getgain, - }, -}; - static const struct v4l2_pix_format sif_mode[] = { {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE, .bytesperline = 176, @@ -167,39 +92,44 @@ static const __u8 pac207_sensor_init[][8] = { {0x32, 0x00, 0x96, 0x00, 0xa2, 0x02, 0xaf, 0x00}, }; -static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, +static void pac207_write_regs(struct gspca_dev *gspca_dev, u16 index, const u8 *buffer, u16 length) { struct usb_device *udev = gspca_dev->dev; int err; + if (gspca_dev->usb_err < 0) + return; + memcpy(gspca_dev->usb_buf, buffer, length); err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 0x00, index, gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT); - if (err < 0) + if (err < 0) { pr_err("Failed to write registers to index 0x%04X, error %d\n", index, err); - - return err; + gspca_dev->usb_err = err; + } } - -static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value) +static void pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value) { struct usb_device *udev = gspca_dev->dev; int err; + if (gspca_dev->usb_err < 0) + return; + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, value, index, NULL, 0, PAC207_CTRL_TIMEOUT); - if (err) + if (err) { pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n", index, value, err); - - return err; + gspca_dev->usb_err = err; + } } static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) @@ -207,6 +137,9 @@ static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) struct usb_device *udev = gspca_dev->dev; int res; + if (gspca_dev->usb_err < 0) + return 0; + res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE, 0x00, index, @@ -214,7 +147,8 @@ static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) if (res < 0) { pr_err("Failed to read a register (index 0x%04X, error %d)\n", index, res); - return res; + gspca_dev->usb_err = res; + return 0; } return gspca_dev->usb_buf[0]; @@ -224,7 +158,6 @@ static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index) static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { - struct sd *sd = (struct sd *) gspca_dev; struct cam *cam; u8 idreg[2]; @@ -247,10 +180,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; cam->cam_mode = sif_mode; cam->nmodes = ARRAY_SIZE(sif_mode); - sd->brightness = PAC207_BRIGHTNESS_DEFAULT; - sd->exposure = PAC207_EXPOSURE_DEFAULT; - sd->gain = PAC207_GAIN_DEFAULT; - sd->autogain = AUTOGAIN_DEF; return 0; } @@ -264,6 +193,87 @@ static int sd_init(struct gspca_dev *gspca_dev) * Bit_2=Compression test mode enable */ pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ + return gspca_dev->usb_err; +} + +static void setcontrol(struct gspca_dev *gspca_dev, u16 reg, u16 val) +{ + pac207_write_reg(gspca_dev, reg, val); + pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ + pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ +} + +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) { + /* 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. */ + gspca_dev->exposure->val = PAC207_EXPOSURE_DEFAULT; + gspca_dev->gain->val = PAC207_GAIN_DEFAULT; + sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; + } + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + setcontrol(gspca_dev, PAC207_BRIGHTNESS_REG, ctrl->val); + break; + case V4L2_CID_AUTOGAIN: + if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val)) + setcontrol(gspca_dev, PAC207_EXPOSURE_REG, + gspca_dev->exposure->val); + if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val)) + setcontrol(gspca_dev, PAC207_GAIN_REG, + gspca_dev->gain->val); + break; + default: + return -EINVAL; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +/* this function is called at probe time */ +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 4); + + sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, + PAC207_BRIGHTNESS_MIN, PAC207_BRIGHTNESS_MAX, + 1, PAC207_BRIGHTNESS_DEFAULT); + gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, + PAC207_EXPOSURE_MIN, PAC207_EXPOSURE_MAX, + 1, PAC207_EXPOSURE_DEFAULT); + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, + PAC207_GAIN_MIN, PAC207_GAIN_MAX, + 1, PAC207_GAIN_DEFAULT); + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false); return 0; } @@ -285,11 +295,13 @@ static int sd_start(struct gspca_dev *gspca_dev) else pac207_write_reg(gspca_dev, 0x4a, 0x30); pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */ - pac207_write_reg(gspca_dev, 0x08, sd->brightness); + pac207_write_reg(gspca_dev, 0x08, v4l2_ctrl_g_ctrl(sd->brightness)); /* PGA global gain (Bit 4-0) */ - pac207_write_reg(gspca_dev, 0x0e, sd->gain); - pac207_write_reg(gspca_dev, 0x02, sd->exposure); /* PXCK = 12MHz /n */ + pac207_write_reg(gspca_dev, 0x0e, + v4l2_ctrl_g_ctrl(gspca_dev->gain)); + pac207_write_reg(gspca_dev, 0x02, + v4l2_ctrl_g_ctrl(gspca_dev->exposure)); /* PXCK = 12MHz /n */ mode = 0x02; /* Image Format (Bit 0), LED (1), Compr. test mode (2) */ if (gspca_dev->width == 176) { /* 176x144 */ @@ -308,7 +320,7 @@ static int sd_start(struct gspca_dev *gspca_dev) sd->sof_read = 0; sd->autogain_ignore_frames = 0; atomic_set(&sd->avg_lum, -1); - return 0; + return gspca_dev->usb_err; } static void sd_stopN(struct gspca_dev *gspca_dev) @@ -318,8 +330,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ } -/* Include pac common sof detection functions */ -#include "pac_common.h" static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) { @@ -331,9 +341,8 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) if (sd->autogain_ignore_frames > 0) sd->autogain_ignore_frames--; - else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, - 90, PAC207_AUTOGAIN_DEADZONE, - PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) + else if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum, + 90, PAC207_AUTOGAIN_DEADZONE)) sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; } @@ -384,118 +393,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - pac207_write_reg(gspca_dev, 0x08, sd->brightness); - pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ - pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ -} - -static void setexposure(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - pac207_write_reg(gspca_dev, 0x02, sd->exposure); - pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ - pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ -} - -static void setgain(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - - pac207_write_reg(gspca_dev, 0x0e, sd->gain); - pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */ - pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */ -} - -static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->brightness = val; - if (gspca_dev->streaming) - setbrightness(gspca_dev); - return 0; -} - -static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->brightness; - 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_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_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->autogain = val; - /* 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 = PAC207_EXPOSURE_DEFAULT; - sd->gain = PAC207_GAIN_DEFAULT; - if (gspca_dev->streaming) { - sd->autogain_ignore_frames = - PAC_AUTOGAIN_IGNORE_FRAMES; - setexposure(gspca_dev); - setgain(gspca_dev); - } - } - - return 0; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* interrupt packet data */ @@ -518,10 +415,9 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, /* sub-driver description */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, .dq_callback = pac207_do_auto_gain, diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index 30662fccb0c..a0369a58c4b 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c @@ -23,43 +23,58 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* Some documentation about various registers as determined by trial and error. - - Register page 1: - - Address Description - 0x78 Global control, bit 6 controls the LED (inverted) - - Register page 3: - - Address Description - 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on - the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? - 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps - 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps, - 63 -> ~27 fps, the 2 msb's must always be 1 !! - 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0: - 1 -> ~30 fps, 2 -> ~20 fps - 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time - 0x0f Exposure bit 8, 0-448, 448 = no exposure at all - 0x10 Master gain 0-31 - 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused - - The registers are accessed in the following functions: - - Page | Register | Function - -----+------------+--------------------------------------------------- - 0 | 0x0f..0x20 | setcolors() - 0 | 0xa2..0xab | setbrightcont() - 0 | 0xc5 | setredbalance() - 0 | 0xc6 | setwhitebalance() - 0 | 0xc7 | setbluebalance() - 0 | 0xdc | setbrightcont(), setcolors() - 3 | 0x02 | setexposure() - 3 | 0x10 | setgain() - 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip() - 3 | 0x21 | sethvflip() -*/ +/* + * Some documentation about various registers as determined by trial and error. + * + * Register page 1: + * + * Address Description + * 0x78 Global control, bit 6 controls the LED (inverted) + * 0x80 Compression balance, 2 interesting settings: + * 0x0f Default + * 0x50 Values >= this switch the camera to a lower compression, + * using the same table for both luminance and chrominance. + * This gives a sharper picture. Only usable when running + * at < 15 fps! Note currently the driver does not use this + * as the quality gain is small and the generated JPG-s are + * only understood by v4l-utils >= 0.8.9 + * + * Register page 3: + * + * Address Description + * 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on + * the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? + * 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps + * 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps, + * 63 -> ~27 fps, the 2 msb's must always be 1 !! + * 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0: + * 1 -> ~30 fps, 2 -> ~20 fps + * 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time + * 0x0f Exposure bit 8, 0-448, 448 = no exposure at all + * 0x10 Gain 0-31 + * 0x12 Another gain 0-31, unlike 0x10 this one seems to start with an + * amplification value of 1 rather then 0 at its lowest setting + * 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused + * 0x80 Another framerate control, best left at 1, moving it from 1 to + * 2 causes the framerate to become 3/4th of what it was, and + * also seems to cause pixel averaging, resulting in an effective + * resolution of 320x240 and thus a much blockier image + * + * The registers are accessed in the following functions: + * + * Page | Register | Function + * -----+------------+--------------------------------------------------- + * 0 | 0x0f..0x20 | setcolors() + * 0 | 0xa2..0xab | setbrightcont() + * 0 | 0xc5 | setredbalance() + * 0 | 0xc6 | setwhitebalance() + * 0 | 0xc7 | setbluebalance() + * 0 | 0xdc | setbrightcont(), setcolors() + * 3 | 0x02 | setexposure() + * 3 | 0x10, 0x12 | setgain() + * 3 | 0x11 | setcolors(), setgain(), setexposure(), sethvflip() + * 3 | 0x21 | sethvflip() + */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -89,7 +104,6 @@ enum e_ctrl { NCTRLS /* number of controls */ }; -/* specific webcam descriptor for pac7302 */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ @@ -198,10 +212,10 @@ static const struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Gain", .minimum = 0, - .maximum = 255, + .maximum = 62, .step = 1, -#define GAIN_DEF 127 -#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */ +#define GAIN_DEF 15 +#define GAIN_KNEE 46 .default_value = GAIN_DEF, }, .set_control = setgain @@ -270,7 +284,6 @@ static const struct v4l2_pix_format vga_mode[] = { #define LOAD_PAGE3 255 #define END_OF_SEQUENCE 0 -/* pac 7302 */ static const u8 init_7302[] = { /* index,value */ 0xff, 0x01, /* page 1 */ @@ -509,7 +522,6 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } -/* This function is used by pac7302 only */ static void setbrightcont(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -536,7 +548,6 @@ static void setbrightcont(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0xdc, 0x01); } -/* This function is used by pac7302 only */ static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -590,9 +601,19 @@ static void setbluebalance(struct gspca_dev *gspca_dev) static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; + u8 reg10, reg12; + + if (sd->ctrls[GAIN].val < 32) { + reg10 = sd->ctrls[GAIN].val; + reg12 = 0; + } else { + reg10 = 31; + reg12 = sd->ctrls[GAIN].val - 31; + } reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ - reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3); + reg_w(gspca_dev, 0x10, reg10); + reg_w(gspca_dev, 0x12, reg12); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); @@ -604,28 +625,36 @@ static void setexposure(struct gspca_dev *gspca_dev) u8 clockdiv; u16 exposure; - /* register 2 of frame 3 contains the clock divider configuring the - no fps according to the formula: 90 / reg. sd->exposure is the - desired exposure time in 0.5 ms. */ + /* + * Register 2 of frame 3 contains the clock divider configuring the + * no fps according to the formula: 90 / reg. sd->exposure is the + * desired exposure time in 0.5 ms. + */ clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000; - /* Note clockdiv = 3 also works, but when running at 30 fps, depending - on the scene being recorded, the camera switches to another - quantization table for certain JPEG blocks, and we don't know how - to decompress these blocks. So we cap the framerate at 15 fps */ + /* + * Note clockdiv = 3 also works, but when running at 30 fps, depending + * on the scene being recorded, the camera switches to another + * quantization table for certain JPEG blocks, and we don't know how + * to decompress these blocks. So we cap the framerate at 15 fps. + */ if (clockdiv < 6) clockdiv = 6; else if (clockdiv > 63) clockdiv = 63; - /* reg2 MUST be a multiple of 3, except when between 6 and 12? - Always round up, otherwise we cannot get the desired frametime - using the partial frame time exposure control */ + /* + * Register 2 MUST be a multiple of 3, except when between 6 and 12? + * Always round up, otherwise we cannot get the desired frametime + * using the partial frame time exposure control. + */ if (clockdiv < 6 || clockdiv > 12) clockdiv = ((clockdiv + 2) / 3) * 3; - /* frame exposure time in ms = 1000 * clockdiv / 90 -> - exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ + /* + * frame exposure time in ms = 1000 * clockdiv / 90 -> + * exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) + */ exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv); /* 0 = use full frametime, 448 = no exposure, reverse it */ exposure = 448 - exposure; @@ -643,10 +672,12 @@ static void setautogain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) 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. */ + /* + * 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->ctrls[AUTOGAIN].val) { sd->ctrls[EXPOSURE].val = EXPOSURE_DEF; sd->ctrls[GAIN].val = GAIN_DEF; @@ -700,8 +731,6 @@ static int sd_start(struct gspca_dev *gspca_dev) setautogain(gspca_dev); sethvflip(gspca_dev); - /* only resolution 640x480 is supported for pac7302 */ - sd->sof_read = 0; atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val); @@ -729,9 +758,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x78, 0x40); } -/* !! coarse_grained_expo_autogain is not used !! */ -#define exp_too_low_cnt flags -#define exp_too_high_cnt sof_read +#define WANT_REGULAR_AUTOGAIN #include "autogain_functions.h" static void do_autogain(struct gspca_dev *gspca_dev) @@ -792,10 +819,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, if (sof) { int n, lum_offset, footer_length; - /* 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 */ + /* + * 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; @@ -839,9 +868,10 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev, u8 index; u8 value; - /* reg->reg: bit0..15: reserved for register index (wIndex is 16bit - long on the USB bus) - */ + /* + * reg->reg: bit0..15: reserved for register index (wIndex is 16bit + * long on the USB bus) + */ if (reg->match.type == V4L2_CHIP_MATCH_HOST && reg->match.addr == 0 && (reg->reg < 0x000000ff) && @@ -852,9 +882,11 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev, index = reg->reg; value = reg->val; - /* Note that there shall be no access to other page - by any other function between the page swith and - the actual register write */ + /* + * Note that there shall be no access to other page + * by any other function between the page switch and + * the actual register write. + */ reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ reg_w(gspca_dev, index, value); @@ -940,6 +972,7 @@ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x2625)}, {USB_DEVICE(0x093a, 0x2626)}, + {USB_DEVICE(0x093a, 0x2627), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x2628)}, {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP}, {USB_DEVICE(0x093a, 0x262a)}, diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index 1ac111176ff..2cb7d95f7be 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c @@ -20,34 +20,42 @@ */ /* 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. -*/ + * + * 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 Compression balance, interesting settings: + * 0x01 Use this to allow the camera to switch to higher compr. + * on the fly. Needed to stay within bandwidth @ 640x480@30 + * 0x1c From usb captures under Windows for 640x480 + * 0x2a Values >= this switch the camera to a lower compression, + * using the same table for both luminance and chrominance. + * This gives a sharper picture. Usable only at 640x480@ < + * 15 fps or 320x240 / 160x120. Note currently the driver + * does not use this as the quality gain is small and the + * generated JPG-s are only understood by v4l-utils >= 0.8.9 + * 0x3f From usb captures under Windows for 320x240 + * 0x69 From usb captures under Windows for 160x120 + * + * Register page 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 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 + * Note setting vflip disabled leads to a much lower image quality, + * so we always vflip, and tell userspace to flip it back + * 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 pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -55,21 +63,21 @@ #include <linux/input.h> #include "gspca.h" +/* Include pac common sof detection functions */ +#include "pac_common.h" + +#define PAC7311_GAIN_DEFAULT 122 +#define PAC7311_EXPOSURE_DEFAULT 3 /* 20 fps, avoid using high compr. */ MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li"); MODULE_DESCRIPTION("Pixart PAC7311"); MODULE_LICENSE("GPL"); -/* specific webcam descriptor for pac7311 */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - unsigned char contrast; - unsigned char gain; - unsigned char exposure; - unsigned char autogain; - __u8 hflip; - __u8 vflip; + struct v4l2_ctrl *contrast; + struct v4l2_ctrl *hflip; u8 sof_read; u8 autogain_ignore_frames; @@ -77,114 +85,6 @@ struct sd { atomic_t avg_lum; }; -/* V4L2 controls supported by the driver */ -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val); -static 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 const struct ctrl sd_ctrls[] = { -/* This control is for both the 7302 and the 7311 */ - { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, -#define CONTRAST_MAX 255 - .maximum = CONTRAST_MAX, - .step = 1, -#define CONTRAST_DEF 127 - .default_value = CONTRAST_DEF, - }, - .set = sd_setcontrast, - .get = sd_getcontrast, - }, -/* 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, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, - }, - .set = sd_setautogain, - .get = sd_getautogain, - }, - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Mirror", - .minimum = 0, - .maximum = 1, - .step = 1, -#define HFLIP_DEF 0 - .default_value = HFLIP_DEF, - }, - .set = sd_sethflip, - .get = sd_gethflip, - }, - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vflip", - .minimum = 0, - .maximum = 1, - .step = 1, -#define VFLIP_DEF 0 - .default_value = VFLIP_DEF, - }, - .set = sd_setvflip, - .get = sd_getvflip, - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 160, @@ -206,8 +106,8 @@ static const struct v4l2_pix_format vga_mode[] = { #define LOAD_PAGE4 254 #define END_OF_SEQUENCE 0 -/* pac 7311 */ static const __u8 init_7311[] = { + 0xff, 0x01, 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 */ @@ -387,90 +287,73 @@ static void reg_w_var(struct gspca_dev *gspca_dev, static int sd_config(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; + struct cam *cam = &gspca_dev->cam; - cam = &gspca_dev->cam; - - PDEBUG(D_CONF, "Find Sensor PAC7311"); cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); + cam->input_flags = V4L2_IN_ST_VFLIP; - sd->contrast = CONTRAST_DEF; - sd->gain = GAIN_DEF; - sd->exposure = EXPOSURE_DEF; - sd->autogain = AUTOGAIN_DEF; - sd->hflip = HFLIP_DEF; - sd->vflip = VFLIP_DEF; return 0; } -/* This function is used by pac7311 only */ -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - reg_w(gspca_dev, 0xff, 0x04); - reg_w(gspca_dev, 0x10, sd->contrast >> 4); + reg_w(gspca_dev, 0x10, val); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); } -static void setgain(struct gspca_dev *gspca_dev) +static void setgain(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - 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, 0x0f, gspca_dev->gain->maximum - val + 1); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); } -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - __u8 reg; - - /* 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; - reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ - reg_w(gspca_dev, 0x02, reg); + reg_w(gspca_dev, 0x02, val); - /* 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 */ + /* load registers to sensor (Bit 0, auto clear) */ + reg_w(gspca_dev, 0x11, 0x01); + + /* + * Page 1 register 8 must always be 0x08 except when not in + * 640x480 mode and page 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) { + if (gspca_dev->width != 640 && val <= 3) reg_w(gspca_dev, 0x08, 0x09); - } else { + else reg_w(gspca_dev, 0x08, 0x08); - } + + /* + * Page1 register 80 sets the compression balance, normally we + * want / use 0x1c, but for 640x480@30fps we must allow the + * camera to use higher compression or we may run out of + * bandwidth. + */ + if (gspca_dev->width == 640 && val == 2) + reg_w(gspca_dev, 0x80, 0x01); + else + reg_w(gspca_dev, 0x80, 0x1c); /* load registers to sensor (Bit 0, auto clear) */ reg_w(gspca_dev, 0x11, 0x01); } -static void sethvflip(struct gspca_dev *gspca_dev) +static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip) { - struct sd *sd = (struct sd *) gspca_dev; __u8 data; reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ - data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00); + data = (hflip ? 0x04 : 0x00) | + (vflip ? 0x08 : 0x00); reg_w(gspca_dev, 0x21, data); /* load registers to sensor (Bit 0, auto clear) */ @@ -484,6 +367,82 @@ static int sd_init(struct gspca_dev *gspca_dev) return gspca_dev->usb_err; } +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) { + /* 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. */ + gspca_dev->exposure->val = PAC7311_EXPOSURE_DEFAULT; + gspca_dev->gain->val = PAC7311_GAIN_DEFAULT; + sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; + } + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + case V4L2_CID_CONTRAST: + setcontrast(gspca_dev, ctrl->val); + break; + case V4L2_CID_AUTOGAIN: + if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val)) + setexposure(gspca_dev, gspca_dev->exposure->val); + if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val)) + setgain(gspca_dev, gspca_dev->gain->val); + break; + case V4L2_CID_HFLIP: + sethvflip(gspca_dev, sd->hflip->val, 1); + break; + default: + return -EINVAL; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +/* this function is called at probe time */ +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 4); + + sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 15, 1, 7); + gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 2, 63, 1, + PAC7311_EXPOSURE_DEFAULT); + gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 244, 1, + PAC7311_GAIN_DEFAULT); + sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + + v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false); + return 0; +} + +/* -- start the camera -- */ static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -492,19 +451,19 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w_var(gspca_dev, start_7311, page4_7311, sizeof(page4_7311)); - setcontrast(gspca_dev); - setgain(gspca_dev); - setexposure(gspca_dev); - sethvflip(gspca_dev); + setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->contrast)); + setgain(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->gain)); + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure)); + sethvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), 1); /* set correct resolution */ switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { - case 2: /* 160x120 pac7311 */ + case 2: /* 160x120 */ reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x17, 0x20); reg_w(gspca_dev, 0x87, 0x10); break; - case 1: /* 320x240 pac7311 */ + case 1: /* 320x240 */ reg_w(gspca_dev, 0xff, 0x01); reg_w(gspca_dev, 0x17, 0x30); reg_w(gspca_dev, 0x87, 0x11); @@ -541,14 +500,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x78, 0x44); /* Bit_0=start stream, Bit_6=LED */ } -/* called on streamoff with alt 0 and on disconnect for 7311 */ -static void sd_stop0(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; @@ -558,13 +509,13 @@ static void do_autogain(struct gspca_dev *gspca_dev) if (avg_lum == -1) return; - desired_lum = 200; + desired_lum = 170; 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)) + else if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum, + desired_lum, deadzone)) sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; } @@ -628,10 +579,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, if (sof) { int n, lum_offset, footer_length; - /* 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 */ + /* + * 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 = 24 + sizeof pac_sof_marker; footer_length = 26; @@ -668,127 +621,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->contrast = val; - if (gspca_dev->streaming) - setcontrast(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->contrast; - return 0; -} - -static int sd_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 gspca_dev->usb_err; -} - -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 gspca_dev->usb_err; -} - -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; - /* 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 gspca_dev->usb_err; -} - -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->autogain; - return 0; -} - -static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->hflip = val; - if (gspca_dev->streaming) - sethvflip(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->hflip; - return 0; -} - -static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->vflip = val; - if (gspca_dev->streaming) - sethvflip(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - *val = sd->vflip; - return 0; -} - #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, u8 *data, /* interrupt packet data */ @@ -820,16 +652,13 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, } #endif -/* sub-driver description for pac7311 */ static const struct sd_desc sd_desc = { .name = MODULE_NAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .start = sd_start, .stopN = sd_stopN, - .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, .dq_callback = do_autogain, #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c index 7e71aa2d252..ad098202d7f 100644 --- a/drivers/media/video/gspca/sn9c20x.c +++ b/drivers/media/video/gspca/sn9c20x.c @@ -59,35 +59,38 @@ MODULE_LICENSE("GPL"); #define SENSOR_MT9M111 9 #define SENSOR_MT9M112 10 #define SENSOR_HV7131R 11 -#define SENSOR_MT9VPRB 20 +#define SENSOR_MT9VPRB 12 /* camera flags */ #define HAS_NO_BUTTON 0x1 #define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */ #define FLIP_DETECT 0x4 -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - SATURATION, - HUE, - GAMMA, - BLUE, - RED, - VFLIP, - HFLIP, - EXPOSURE, - GAIN, - AUTOGAIN, - QUALITY, - NCTRLS /* number of controls */ -}; - /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; - struct gspca_ctrl ctrls[NCTRLS]; + struct { /* color control cluster */ + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *contrast; + struct v4l2_ctrl *saturation; + struct v4l2_ctrl *hue; + }; + struct { /* blue/red balance control cluster */ + struct v4l2_ctrl *blue; + struct v4l2_ctrl *red; + }; + struct { /* h/vflip control cluster */ + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + }; + struct v4l2_ctrl *gamma; + struct { /* autogain and exposure or gain control cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *gain; + }; + struct v4l2_ctrl *jpegqual; struct work_struct work; struct workqueue_struct *work_thread; @@ -105,6 +108,7 @@ struct sd { u8 exposure_step; u8 i2c_addr; + u8 i2c_intf; u8 sensor; u8 hstart; u8 vstart; @@ -166,175 +170,6 @@ static const struct dmi_system_id flip_dmi_table[] = { {} }; -static void set_cmatrix(struct gspca_dev *gspca_dev); -static void set_gamma(struct gspca_dev *gspca_dev); -static void set_redblue(struct gspca_dev *gspca_dev); -static void set_hvflip(struct gspca_dev *gspca_dev); -static void set_exposure(struct gspca_dev *gspca_dev); -static void set_gain(struct gspca_dev *gspca_dev); -static void set_quality(struct gspca_dev *gspca_dev); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f - }, - .set_control = set_cmatrix - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f - }, - .set_control = set_cmatrix - }, -[SATURATION] = { - { - .id = V4L2_CID_SATURATION, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Saturation", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f - }, - .set_control = set_cmatrix - }, -[HUE] = { - { - .id = V4L2_CID_HUE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Hue", - .minimum = -180, - .maximum = 180, - .step = 1, - .default_value = 0 - }, - .set_control = set_cmatrix - }, -[GAMMA] = { - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x10 - }, - .set_control = set_gamma - }, -[BLUE] = { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = 0, - .maximum = 0x7f, - .step = 1, - .default_value = 0x28 - }, - .set_control = set_redblue - }, -[RED] = { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = 0, - .maximum = 0x7f, - .step = 1, - .default_value = 0x28 - }, - .set_control = set_redblue - }, -[HFLIP] = { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Horizontal Flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = set_hvflip - }, -[VFLIP] = { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Vertical Flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0, - }, - .set_control = set_hvflip - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 0x1780, - .step = 1, - .default_value = 0x33, - }, - .set_control = set_exposure - }, -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 28, - .step = 1, - .default_value = 0, - }, - .set_control = set_gain - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - }, - }, -[QUALITY] = { - { - .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Compression Quality", -#define QUALITY_MIN 50 -#define QUALITY_MAX 90 -#define QUALITY_DEF 80 - .minimum = QUALITY_MIN, - .maximum = QUALITY_MAX, - .step = 1, - .default_value = QUALITY_DEF, - }, - .set_control = set_quality - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 160, @@ -747,7 +582,7 @@ static const s16 hsv_blue_y[] = { 4, 2, 0, -1, -3, -5, -7, -9, -11 }; -static u16 i2c_ident[] = { +static const u16 i2c_ident[] = { V4L2_IDENT_OV9650, V4L2_IDENT_OV9655, V4L2_IDENT_SOI968, @@ -760,9 +595,10 @@ static u16 i2c_ident[] = { V4L2_IDENT_MT9M111, V4L2_IDENT_MT9M112, V4L2_IDENT_HV7131R, +[SENSOR_MT9VPRB] = V4L2_IDENT_UNKNOWN, }; -static u16 bridge_init[][2] = { +static const u16 bridge_init[][2] = { {0x1000, 0x78}, {0x1001, 0x40}, {0x1002, 0x1c}, {0x1020, 0x80}, {0x1061, 0x01}, {0x1067, 0x40}, {0x1068, 0x30}, {0x1069, 0x20}, {0x106a, 0x10}, @@ -786,7 +622,7 @@ static u16 bridge_init[][2] = { }; /* Gain = (bit[3:0] / 16 + 1) * (bit[4] + 1) * (bit[5] + 1) * (bit[6] + 1) */ -static u8 ov_gain[] = { +static const u8 ov_gain[] = { 0x00 /* 1x */, 0x04 /* 1.25x */, 0x08 /* 1.5x */, 0x0c /* 1.75x */, 0x10 /* 2x */, 0x12 /* 2.25x */, 0x14 /* 2.5x */, 0x16 /* 2.75x */, 0x18 /* 3x */, 0x1a /* 3.25x */, 0x1c /* 3.5x */, 0x1e /* 3.75x */, @@ -798,7 +634,7 @@ static u8 ov_gain[] = { }; /* Gain = (bit[8] + 1) * (bit[7] + 1) * (bit[6:0] * 0.03125) */ -static u16 micron1_gain[] = { +static const u16 micron1_gain[] = { /* 1x 1.25x 1.5x 1.75x */ 0x0020, 0x0028, 0x0030, 0x0038, /* 2x 2.25x 2.5x 2.75x */ @@ -819,7 +655,7 @@ static u16 micron1_gain[] = { /* mt9m001 sensor uses a different gain formula then other micron sensors */ /* Gain = (bit[6] + 1) * (bit[5-0] * 0.125) */ -static u16 micron2_gain[] = { +static const u16 micron2_gain[] = { /* 1x 1.25x 1.5x 1.75x */ 0x0008, 0x000a, 0x000c, 0x000e, /* 2x 2.25x 2.5x 2.75x */ @@ -839,7 +675,7 @@ static u16 micron2_gain[] = { }; /* Gain = .5 + bit[7:0] / 16 */ -static u8 hv7131r_gain[] = { +static const u8 hv7131r_gain[] = { 0x08 /* 1x */, 0x0c /* 1.25x */, 0x10 /* 1.5x */, 0x14 /* 1.75x */, 0x18 /* 2x */, 0x1c /* 2.25x */, 0x20 /* 2.5x */, 0x24 /* 2.75x */, 0x28 /* 3x */, 0x2c /* 3.25x */, 0x30 /* 3.5x */, 0x34 /* 3.75x */, @@ -850,7 +686,7 @@ static u8 hv7131r_gain[] = { 0x78 /* 8x */ }; -static struct i2c_reg_u8 soi968_init[] = { +static const struct i2c_reg_u8 soi968_init[] = { {0x0c, 0x00}, {0x0f, 0x1f}, {0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00}, {0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c}, @@ -864,7 +700,7 @@ static struct i2c_reg_u8 soi968_init[] = { {0x00, 0x00}, {0x01, 0x80}, {0x02, 0x80}, }; -static struct i2c_reg_u8 ov7660_init[] = { +static const struct i2c_reg_u8 ov7660_init[] = { {0x0e, 0x80}, {0x0d, 0x08}, {0x0f, 0xc3}, {0x04, 0xc3}, {0x10, 0x40}, {0x11, 0x40}, {0x12, 0x05}, {0x13, 0xba}, {0x14, 0x2a}, @@ -872,11 +708,11 @@ static struct i2c_reg_u8 ov7660_init[] = { 0x10, 0x61 and sd->hstart, vstart = 3, fixes ugly colored borders */ {0x17, 0x10}, {0x18, 0x61}, {0x37, 0x0f}, {0x38, 0x02}, {0x39, 0x43}, - {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0xf6}, - {0x2e, 0x0b}, {0x01, 0x78}, {0x02, 0x50}, + {0x3a, 0x00}, {0x69, 0x90}, {0x2d, 0x00}, + {0x2e, 0x00}, {0x01, 0x78}, {0x02, 0x50}, }; -static struct i2c_reg_u8 ov7670_init[] = { +static const struct i2c_reg_u8 ov7670_init[] = { {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01}, {0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00}, {0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0}, @@ -933,7 +769,7 @@ static struct i2c_reg_u8 ov7670_init[] = { {0x93, 0x00}, }; -static struct i2c_reg_u8 ov9650_init[] = { +static const struct i2c_reg_u8 ov9650_init[] = { {0x00, 0x00}, {0x01, 0x78}, {0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03}, {0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00}, @@ -963,7 +799,7 @@ static struct i2c_reg_u8 ov9650_init[] = { {0xaa, 0x92}, {0xab, 0x0a}, }; -static struct i2c_reg_u8 ov9655_init[] = { +static const struct i2c_reg_u8 ov9655_init[] = { {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba}, {0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08}, {0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d}, @@ -990,7 +826,7 @@ static struct i2c_reg_u8 ov9655_init[] = { {0x04, 0x03}, {0x00, 0x13}, }; -static struct i2c_reg_u16 mt9v112_init[] = { +static const struct i2c_reg_u16 mt9v112_init[] = { {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0020}, {0x34, 0xc019}, {0x0a, 0x0011}, {0x0b, 0x000b}, {0x20, 0x0703}, {0x35, 0x2022}, {0xf0, 0x0001}, @@ -1009,7 +845,7 @@ static struct i2c_reg_u16 mt9v112_init[] = { {0x2c, 0x00ae}, {0x2d, 0x00ae}, {0x2e, 0x00ae}, }; -static struct i2c_reg_u16 mt9v111_init[] = { +static const struct i2c_reg_u16 mt9v111_init[] = { {0x01, 0x0004}, {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x0001}, {0x05, 0x0004}, {0x2d, 0xe0a0}, {0x2e, 0x0c64}, {0x2f, 0x0064}, {0x06, 0x600e}, @@ -1019,7 +855,7 @@ static struct i2c_reg_u16 mt9v111_init[] = { {0x0e, 0x0008}, {0x20, 0x0000} }; -static struct i2c_reg_u16 mt9v011_init[] = { +static const struct i2c_reg_u16 mt9v011_init[] = { {0x07, 0x0002}, {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x0008}, {0x02, 0x0016}, {0x03, 0x01e1}, {0x04, 0x0281}, {0x05, 0x0083}, {0x06, 0x0006}, @@ -1046,7 +882,7 @@ static struct i2c_reg_u16 mt9v011_init[] = { {0x06, 0x0029}, {0x05, 0x0009}, }; -static struct i2c_reg_u16 mt9m001_init[] = { +static const struct i2c_reg_u16 mt9m001_init[] = { {0x0d, 0x0001}, {0x0d, 0x0000}, {0x04, 0x0500}, /* hres = 1280 */ @@ -1062,21 +898,21 @@ static struct i2c_reg_u16 mt9m001_init[] = { {0x35, 0x0057}, }; -static struct i2c_reg_u16 mt9m111_init[] = { +static const struct i2c_reg_u16 mt9m111_init[] = { {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008}, {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300}, {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e}, {0xf0, 0x0000}, }; -static struct i2c_reg_u16 mt9m112_init[] = { +static const struct i2c_reg_u16 mt9m112_init[] = { {0xf0, 0x0000}, {0x0d, 0x0021}, {0x0d, 0x0008}, {0xf0, 0x0001}, {0x3a, 0x4300}, {0x9b, 0x4300}, {0x06, 0x708e}, {0xf0, 0x0002}, {0x2e, 0x0a1e}, {0xf0, 0x0000}, }; -static struct i2c_reg_u8 hv7131r_init[] = { +static const struct i2c_reg_u8 hv7131r_init[] = { {0x02, 0x08}, {0x02, 0x00}, {0x01, 0x08}, {0x02, 0x00}, {0x20, 0x00}, {0x21, 0xd0}, {0x22, 0x00}, {0x23, 0x09}, {0x01, 0x08}, @@ -1167,7 +1003,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) * from the point of view of the bridge, the length * includes the address */ - row[0] = 0x81 | (2 << 4); + row[0] = sd->i2c_intf | (2 << 4); row[1] = sd->i2c_addr; row[2] = reg; row[3] = val; @@ -1180,7 +1016,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val) } static void i2c_w1_buf(struct gspca_dev *gspca_dev, - struct i2c_reg_u8 *buf, int sz) + const struct i2c_reg_u8 *buf, int sz) { while (--sz >= 0) { i2c_w1(gspca_dev, buf->reg, buf->val); @@ -1197,7 +1033,7 @@ static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) * from the point of view of the bridge, the length * includes the address */ - row[0] = 0x81 | (3 << 4); + row[0] = sd->i2c_intf | (3 << 4); row[1] = sd->i2c_addr; row[2] = reg; row[3] = val >> 8; @@ -1210,7 +1046,7 @@ static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val) } static void i2c_w2_buf(struct gspca_dev *gspca_dev, - struct i2c_reg_u16 *buf, int sz) + const struct i2c_reg_u16 *buf, int sz) { while (--sz >= 0) { i2c_w2(gspca_dev, buf->reg, buf->val); @@ -1223,7 +1059,7 @@ static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) struct sd *sd = (struct sd *) gspca_dev; u8 row[8]; - row[0] = 0x81 | (1 << 4); + row[0] = sd->i2c_intf | (1 << 4); row[1] = sd->i2c_addr; row[2] = reg; row[3] = 0; @@ -1232,7 +1068,7 @@ static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val) row[6] = 0; row[7] = 0x10; i2c_w(gspca_dev, row); - row[0] = 0x81 | (1 << 4) | 0x02; + row[0] = sd->i2c_intf | (1 << 4) | 0x02; row[2] = 0; i2c_w(gspca_dev, row); reg_r(gspca_dev, 0x10c2, 5); @@ -1244,7 +1080,7 @@ static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) struct sd *sd = (struct sd *) gspca_dev; u8 row[8]; - row[0] = 0x81 | (1 << 4); + row[0] = sd->i2c_intf | (1 << 4); row[1] = sd->i2c_addr; row[2] = reg; row[3] = 0; @@ -1253,7 +1089,7 @@ static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val) row[6] = 0; row[7] = 0x10; i2c_w(gspca_dev, row); - row[0] = 0x81 | (2 << 4) | 0x02; + row[0] = sd->i2c_intf | (2 << 4) | 0x02; row[2] = 0; i2c_w(gspca_dev, row); reg_r(gspca_dev, 0x10c2, 5); @@ -1294,8 +1130,6 @@ static void ov9655_init_sensor(struct gspca_dev *gspca_dev) if (gspca_dev->usb_err < 0) pr_err("OV9655 sensor initialization failed\n"); - /* disable hflip and vflip */ - gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); sd->hstart = 1; sd->vstart = 2; } @@ -1310,9 +1144,6 @@ static void soi968_init_sensor(struct gspca_dev *gspca_dev) if (gspca_dev->usb_err < 0) pr_err("SOI968 sensor initialization failed\n"); - /* disable hflip and vflip */ - gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP) - | (1 << EXPOSURE); sd->hstart = 60; sd->vstart = 11; } @@ -1340,8 +1171,6 @@ static void ov7670_init_sensor(struct gspca_dev *gspca_dev) if (gspca_dev->usb_err < 0) pr_err("OV7670 sensor initialization failed\n"); - /* disable hflip and vflip */ - gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); sd->hstart = 0; sd->vstart = 1; } @@ -1378,9 +1207,6 @@ static void mt9v_init_sensor(struct gspca_dev *gspca_dev) pr_err("MT9V111 sensor initialization failed\n"); return; } - gspca_dev->ctrl_dis = (1 << EXPOSURE) - | (1 << AUTOGAIN) - | (1 << GAIN); sd->hstart = 2; sd->vstart = 2; sd->sensor = SENSOR_MT9V111; @@ -1422,8 +1248,6 @@ static void mt9m112_init_sensor(struct gspca_dev *gspca_dev) if (gspca_dev->usb_err < 0) pr_err("MT9M112 sensor initialization failed\n"); - gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN) - | (1 << GAIN); sd->hstart = 0; sd->vstart = 2; } @@ -1436,8 +1260,6 @@ static void mt9m111_init_sensor(struct gspca_dev *gspca_dev) if (gspca_dev->usb_err < 0) pr_err("MT9M111 sensor initialization failed\n"); - gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN) - | (1 << GAIN); sd->hstart = 0; sd->vstart = 2; } @@ -1470,8 +1292,6 @@ static void mt9m001_init_sensor(struct gspca_dev *gspca_dev) if (gspca_dev->usb_err < 0) pr_err("MT9M001 sensor initialization failed\n"); - /* disable hflip and vflip */ - gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP); sd->hstart = 1; sd->vstart = 1; } @@ -1488,20 +1308,18 @@ static void hv7131r_init_sensor(struct gspca_dev *gspca_dev) sd->vstart = 1; } -static void set_cmatrix(struct gspca_dev *gspca_dev) +static void set_cmatrix(struct gspca_dev *gspca_dev, + s32 brightness, s32 contrast, s32 satur, s32 hue) { - struct sd *sd = (struct sd *) gspca_dev; - int satur; - s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val; + s32 hue_coord, hue_index = 180 + hue; u8 cmatrix[21]; memset(cmatrix, 0, sizeof cmatrix); - cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26; + cmatrix[2] = (contrast * 0x25 / 0x100) + 0x26; cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25; cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25; - cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80; + cmatrix[18] = brightness - 0x80; - satur = sd->ctrls[SATURATION].val; hue_coord = (hsv_red_x[hue_index] * satur) >> 8; cmatrix[6] = hue_coord; cmatrix[7] = (hue_coord >> 8) & 0x0f; @@ -1529,11 +1347,10 @@ static void set_cmatrix(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x10e1, cmatrix, 21); } -static void set_gamma(struct gspca_dev *gspca_dev) +static void set_gamma(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; u8 gamma[17]; - u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100; + u8 gval = val * 0xb8 / 0x100; gamma[0] = 0x0a; gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8); @@ -1556,26 +1373,21 @@ static void set_gamma(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x1190, gamma, 17); } -static void set_redblue(struct gspca_dev *gspca_dev) +static void set_redblue(struct gspca_dev *gspca_dev, s32 blue, s32 red) { - struct sd *sd = (struct sd *) gspca_dev; - - reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val); - reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val); + reg_w1(gspca_dev, 0x118c, red); + reg_w1(gspca_dev, 0x118f, blue); } -static void set_hvflip(struct gspca_dev *gspca_dev) +static void set_hvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip) { - u8 value, tslb, hflip, vflip; + u8 value, tslb; u16 value2; struct sd *sd = (struct sd *) gspca_dev; if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) { - hflip = !sd->ctrls[HFLIP].val; - vflip = !sd->ctrls[VFLIP].val; - } else { - hflip = sd->ctrls[HFLIP].val; - vflip = sd->ctrls[VFLIP].val; + hflip = !hflip; + vflip = !vflip; } switch (sd->sensor) { @@ -1638,20 +1450,38 @@ static void set_hvflip(struct gspca_dev *gspca_dev) } } -static void set_exposure(struct gspca_dev *gspca_dev) +static void set_exposure(struct gspca_dev *gspca_dev, s32 expo) { struct sd *sd = (struct sd *) gspca_dev; - u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e}; - int expo; + u8 exp[8] = {sd->i2c_intf, sd->i2c_addr, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; + int expo2; + + if (gspca_dev->streaming) + exp[7] = 0x1e; - expo = sd->ctrls[EXPOSURE].val; switch (sd->sensor) { case SENSOR_OV7660: case SENSOR_OV7670: case SENSOR_OV9655: case SENSOR_OV9650: + if (expo > 547) + expo2 = 547; + else + expo2 = expo; + exp[0] |= (2 << 4); + exp[2] = 0x10; /* AECH */ + exp[3] = expo2 >> 2; + exp[7] = 0x10; + i2c_w(gspca_dev, exp); + exp[2] = 0x04; /* COM1 */ + exp[3] = expo2 & 0x0003; + exp[7] = 0x10; + i2c_w(gspca_dev, exp); + expo -= expo2; + exp[7] = 0x1e; exp[0] |= (3 << 4); - exp[2] = 0x2d; + exp[2] = 0x2d; /* ADVFL & ADVFH */ exp[3] = expo; exp[4] = expo >> 8; break; @@ -1676,13 +1506,15 @@ static void set_exposure(struct gspca_dev *gspca_dev) i2c_w(gspca_dev, exp); } -static void set_gain(struct gspca_dev *gspca_dev) +static void set_gain(struct gspca_dev *gspca_dev, s32 g) { struct sd *sd = (struct sd *) gspca_dev; - u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d}; - int g; + u8 gain[8] = {sd->i2c_intf, sd->i2c_addr, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}; + + if (gspca_dev->streaming) + gain[7] = 0x15; /* or 1d ? */ - g = sd->ctrls[GAIN].val; switch (sd->sensor) { case SENSOR_OV7660: case SENSOR_OV7670: @@ -1721,11 +1553,11 @@ static void set_gain(struct gspca_dev *gspca_dev) i2c_w(gspca_dev, gain); } -static void set_quality(struct gspca_dev *gspca_dev) +static void set_quality(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; - jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); + jpeg_set_qual(sd->jpeg_hdr, val); reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */ reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */ reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64); @@ -1827,6 +1659,7 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->sensor = id->driver_info >> 8; sd->i2c_addr = id->driver_info; sd->flags = id->driver_info >> 16; + sd->i2c_intf = 0x80; /* i2c 100 Kb/s */ switch (sd->sensor) { case SENSOR_MT9M112: @@ -1840,6 +1673,9 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = mono_mode; cam->nmodes = ARRAY_SIZE(mono_mode); break; + case SENSOR_HV7131R: + sd->i2c_intf = 0x81; /* i2c 400 Kb/s */ + /* fall thru */ default: cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); @@ -1850,13 +1686,133 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->older_step = 0; sd->exposure_step = 16; - gspca_dev->cam.ctrls = sd->ctrls; - INIT_WORK(&sd->work, qual_upd); return 0; } +static int sd_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + gspca_dev->usb_err = 0; + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + /* color control cluster */ + case V4L2_CID_BRIGHTNESS: + set_cmatrix(gspca_dev, sd->brightness->val, + sd->contrast->val, sd->saturation->val, sd->hue->val); + break; + case V4L2_CID_GAMMA: + set_gamma(gspca_dev, ctrl->val); + break; + /* blue/red balance cluster */ + case V4L2_CID_BLUE_BALANCE: + set_redblue(gspca_dev, sd->blue->val, sd->red->val); + break; + /* h/vflip cluster */ + case V4L2_CID_HFLIP: + set_hvflip(gspca_dev, sd->hflip->val, sd->vflip->val); + break; + /* standalone exposure control */ + case V4L2_CID_EXPOSURE: + set_exposure(gspca_dev, ctrl->val); + break; + /* standalone gain control */ + case V4L2_CID_GAIN: + set_gain(gspca_dev, ctrl->val); + break; + /* autogain + exposure or gain control cluster */ + case V4L2_CID_AUTOGAIN: + if (sd->sensor == SENSOR_SOI968) + set_gain(gspca_dev, sd->gain->val); + else + set_exposure(gspca_dev, sd->exposure->val); + break; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + set_quality(gspca_dev, ctrl->val); + break; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops sd_ctrl_ops = { + .s_ctrl = sd_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 13); + + sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 127); + sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 127); + sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 127); + sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HUE, -180, 180, 1, 0); + v4l2_ctrl_cluster(4, &sd->brightness); + + sd->gamma = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAMMA, 0, 255, 1, 0x10); + + sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_BLUE_BALANCE, 0, 127, 1, 0x28); + sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_RED_BALANCE, 0, 127, 1, 0x28); + v4l2_ctrl_cluster(2, &sd->blue); + + if (sd->sensor != SENSOR_OV9655 && sd->sensor != SENSOR_SOI968 && + sd->sensor != SENSOR_OV7670 && sd->sensor != SENSOR_MT9M001 && + sd->sensor != SENSOR_MT9VPRB) { + sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_cluster(2, &sd->hflip); + } + + if (sd->sensor != SENSOR_SOI968 && sd->sensor != SENSOR_MT9VPRB && + sd->sensor != SENSOR_MT9M112 && sd->sensor != SENSOR_MT9M111 && + sd->sensor != SENSOR_MT9V111) + sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 0x1780, 1, 0x33); + + if (sd->sensor != SENSOR_MT9VPRB && sd->sensor != SENSOR_MT9M112 && + sd->sensor != SENSOR_MT9M111 && sd->sensor != SENSOR_MT9V111) { + sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_GAIN, 0, 28, 1, 0); + sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + if (sd->sensor == SENSOR_SOI968) + /* this sensor doesn't have the exposure control and + autogain is clustered with gain instead. This works + because sd->exposure == NULL. */ + v4l2_ctrl_auto_cluster(3, &sd->autogain, 0, false); + else + /* Otherwise autogain is clustered with exposure. */ + v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false); + } + + sd->jpegqual = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, 50, 90, 1, 80); + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + return 0; +} + static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -1949,7 +1905,6 @@ static int sd_init(struct gspca_dev *gspca_dev) pr_err("Unsupported sensor\n"); gspca_dev->usb_err = -ENODEV; } - return gspca_dev->usb_err; } @@ -2025,8 +1980,8 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) if (intf->num_altsetting != 9) { pr_warn("sn9c20x camera with unknown number of alt " - "settings (%d), please report!\n", - intf->num_altsetting); + "settings (%d), please report!\n", + intf->num_altsetting); gspca_dev->alt = intf->num_altsetting; return 0; } @@ -2067,7 +2022,7 @@ static int sd_start(struct gspca_dev *gspca_dev) jpeg_define(sd->jpeg_hdr, height, width, 0x21); - jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); + jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual)); if (mode & MODE_RAW) fmt = 0x2d; @@ -2104,12 +2059,17 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0x1189, scale); reg_w1(gspca_dev, 0x10e0, fmt); - set_cmatrix(gspca_dev); - set_gamma(gspca_dev); - set_redblue(gspca_dev); - set_gain(gspca_dev); - set_exposure(gspca_dev); - set_hvflip(gspca_dev); + set_cmatrix(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness), + v4l2_ctrl_g_ctrl(sd->contrast), + v4l2_ctrl_g_ctrl(sd->saturation), + v4l2_ctrl_g_ctrl(sd->hue)); + set_gamma(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma)); + set_redblue(gspca_dev, v4l2_ctrl_g_ctrl(sd->blue), + v4l2_ctrl_g_ctrl(sd->red)); + set_gain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain)); + set_exposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure)); + set_hvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), + v4l2_ctrl_g_ctrl(sd->vflip)); reg_w1(gspca_dev, 0x1007, 0x20); reg_w1(gspca_dev, 0x1061, 0x03); @@ -2148,6 +2108,9 @@ static void sd_stop0(struct gspca_dev *gspca_dev) static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) { struct sd *sd = (struct sd *) gspca_dev; + s32 cur_exp = v4l2_ctrl_g_ctrl(sd->exposure); + s32 max = sd->exposure->maximum - sd->exposure_step; + s32 min = sd->exposure->minimum + sd->exposure_step; s16 new_exp; /* @@ -2156,16 +2119,15 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) * and exposure steps */ if (avg_lum < MIN_AVG_LUM) { - if (sd->ctrls[EXPOSURE].val > 0x1770) + if (cur_exp > max) return; - new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step; - if (new_exp > 0x1770) - new_exp = 0x1770; - if (new_exp < 0x10) - new_exp = 0x10; - sd->ctrls[EXPOSURE].val = new_exp; - set_exposure(gspca_dev); + new_exp = cur_exp + sd->exposure_step; + if (new_exp > max) + new_exp = max; + if (new_exp < min) + new_exp = min; + v4l2_ctrl_s_ctrl(sd->exposure, new_exp); sd->older_step = sd->old_step; sd->old_step = 1; @@ -2176,15 +2138,14 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) sd->exposure_step += 2; } if (avg_lum > MAX_AVG_LUM) { - if (sd->ctrls[EXPOSURE].val < 0x10) + if (cur_exp < min) return; - new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step; - if (new_exp > 0x1700) - new_exp = 0x1770; - if (new_exp < 0x10) - new_exp = 0x10; - sd->ctrls[EXPOSURE].val = new_exp; - set_exposure(gspca_dev); + new_exp = cur_exp - sd->exposure_step; + if (new_exp > max) + new_exp = max; + if (new_exp < min) + new_exp = min; + v4l2_ctrl_s_ctrl(sd->exposure, new_exp); sd->older_step = sd->old_step; sd->old_step = 0; @@ -2198,19 +2159,12 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum) static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum) { struct sd *sd = (struct sd *) gspca_dev; + s32 cur_gain = v4l2_ctrl_g_ctrl(sd->gain); - if (avg_lum < MIN_AVG_LUM) { - if (sd->ctrls[GAIN].val + 1 <= 28) { - sd->ctrls[GAIN].val++; - set_gain(gspca_dev); - } - } - if (avg_lum > MAX_AVG_LUM) { - if (sd->ctrls[GAIN].val > 0) { - sd->ctrls[GAIN].val--; - set_gain(gspca_dev); - } - } + if (avg_lum < MIN_AVG_LUM && cur_gain < sd->gain->maximum) + v4l2_ctrl_s_ctrl(sd->gain, cur_gain + 1); + if (avg_lum > MAX_AVG_LUM && cur_gain > sd->gain->minimum) + v4l2_ctrl_s_ctrl(sd->gain, cur_gain - 1); } static void sd_dqcallback(struct gspca_dev *gspca_dev) @@ -2218,7 +2172,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; int avg_lum; - if (!sd->ctrls[AUTOGAIN].val) + if (!v4l2_ctrl_g_ctrl(sd->autogain)) return; avg_lum = atomic_read(&sd->avg_lum); @@ -2234,10 +2188,11 @@ static void qual_upd(struct work_struct *work) { struct sd *sd = container_of(work, struct sd, work); struct gspca_dev *gspca_dev = &sd->gspca_dev; + s32 qual = v4l2_ctrl_g_ctrl(sd->jpegqual); mutex_lock(&gspca_dev->usb_lock); - PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val); - set_quality(gspca_dev); + PDEBUG(D_STREAM, "qual_upd %d%%", qual); + set_quality(gspca_dev, qual); mutex_unlock(&gspca_dev->usb_lock); } @@ -2286,14 +2241,18 @@ static void transfer_check(struct gspca_dev *gspca_dev, if (new_qual != 0) { sd->nchg += new_qual; if (sd->nchg < -6 || sd->nchg >= 12) { + /* Note: we are in interrupt context, so we can't + use v4l2_ctrl_g/s_ctrl here. Access the value + directly instead. */ + s32 curqual = sd->jpegqual->cur.val; sd->nchg = 0; - new_qual += sd->ctrls[QUALITY].val; - if (new_qual < QUALITY_MIN) - new_qual = QUALITY_MIN; - else if (new_qual > QUALITY_MAX) - new_qual = QUALITY_MAX; - if (new_qual != sd->ctrls[QUALITY].val) { - sd->ctrls[QUALITY].val = new_qual; + new_qual += curqual; + if (new_qual < sd->jpegqual->minimum) + new_qual = sd->jpegqual->minimum; + else if (new_qual > sd->jpegqual->maximum) + new_qual = sd->jpegqual->maximum; + if (new_qual != curqual) { + sd->jpegqual->cur.val = new_qual; queue_work(sd->work_thread, &sd->work); } } @@ -2309,7 +2268,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; int avg_lum, is_jpeg; - static u8 frame_header[] = + static const u8 frame_header[] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96}; is_jpeg = (sd->fmt & 0x03) == 0; @@ -2373,10 +2332,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* sub-driver description */ static const struct sd_desc sd_desc = { .name = KBUILD_MODNAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, .isoc_init = sd_isoc_init, .start = sd_start, .stopN = sd_stopN, diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c index 6a1148d7fe9..e2bdf8f632f 100644 --- a/drivers/media/video/gspca/sonixb.c +++ b/drivers/media/video/gspca/sonixb.c @@ -1000,6 +1000,8 @@ static void setfreq(struct gspca_dev *gspca_dev) } } +#define WANT_REGULAR_AUTOGAIN +#define WANT_COARSE_EXPO_AUTOGAIN #include "autogain_functions.h" static void do_autogain(struct gspca_dev *gspca_dev) diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c index 863c755dd2b..4d1696d1a7f 100644 --- a/drivers/media/video/gspca/sonixj.c +++ b/drivers/media/video/gspca/sonixj.c @@ -2800,10 +2800,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev) } } -/* !! coarse_grained_expo_autogain is not used !! */ -#define exp_too_low_cnt bridge -#define exp_too_high_cnt sensor - +#define WANT_REGULAR_AUTOGAIN #include "autogain_functions.h" static void do_autogain(struct gspca_dev *gspca_dev) diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c index 2fe3c29bd6b..04f54654a02 100644 --- a/drivers/media/video/gspca/sq905.c +++ b/drivers/media/video/gspca/sq905.c @@ -232,7 +232,11 @@ static void sq905_dostream(struct work_struct *work) frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage + FRAME_HEADER_LEN; - while (gspca_dev->present && gspca_dev->streaming) { + while (gspca_dev->dev && gspca_dev->streaming) { +#ifdef CONFIG_PM + if (gspca_dev->frozen) + break; +#endif /* request some data and then read it until we have * a complete frame. */ bytes_left = frame_sz; @@ -242,7 +246,7 @@ static void sq905_dostream(struct work_struct *work) we must finish reading an entire frame, otherwise the next time we stream we start reading in the middle of a frame. */ - while (bytes_left > 0 && gspca_dev->present) { + while (bytes_left > 0 && gspca_dev->dev) { data_len = bytes_left > SQ905_MAX_TRANSFER ? SQ905_MAX_TRANSFER : bytes_left; ret = sq905_read_data(gspca_dev, buffer, data_len, 1); @@ -274,7 +278,7 @@ static void sq905_dostream(struct work_struct *work) gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); } - if (gspca_dev->present) { + if (gspca_dev->dev) { /* acknowledge the frame */ mutex_lock(&gspca_dev->usb_lock); ret = sq905_ack_frame(gspca_dev); @@ -284,7 +288,7 @@ static void sq905_dostream(struct work_struct *work) } } quit_stream: - if (gspca_dev->present) { + if (gspca_dev->dev) { mutex_lock(&gspca_dev->usb_lock); sq905_command(gspca_dev, SQ905_CLEAR); mutex_unlock(&gspca_dev->usb_lock); diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c index ae783634712..f34ddb0570c 100644 --- a/drivers/media/video/gspca/sq905c.c +++ b/drivers/media/video/gspca/sq905c.c @@ -150,7 +150,11 @@ static void sq905c_dostream(struct work_struct *work) goto quit_stream; } - while (gspca_dev->present && gspca_dev->streaming) { + while (gspca_dev->dev && gspca_dev->streaming) { +#ifdef CONFIG_PM + if (gspca_dev->frozen) + break; +#endif /* Request the header, which tells the size to download */ ret = usb_bulk_msg(gspca_dev->dev, usb_rcvbulkpipe(gspca_dev->dev, 0x81), @@ -169,7 +173,7 @@ static void sq905c_dostream(struct work_struct *work) packet_type = FIRST_PACKET; gspca_frame_add(gspca_dev, packet_type, buffer, FRAME_HEADER_LEN); - while (bytes_left > 0 && gspca_dev->present) { + while (bytes_left > 0 && gspca_dev->dev) { data_len = bytes_left > SQ905C_MAX_TRANSFER ? SQ905C_MAX_TRANSFER : bytes_left; ret = usb_bulk_msg(gspca_dev->dev, @@ -191,7 +195,7 @@ static void sq905c_dostream(struct work_struct *work) } } quit_stream: - if (gspca_dev->present) { + if (gspca_dev->dev) { mutex_lock(&gspca_dev->usb_lock); sq905c_command(gspca_dev, SQ905C_CLEAR, 0); mutex_unlock(&gspca_dev->usb_lock); diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c index 91d99b4cc57..999ec776444 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx.c @@ -261,6 +261,17 @@ static int stv06xx_init(struct gspca_dev *gspca_dev) return (err < 0) ? err : 0; } +/* this function is called at probe time */ +static int stv06xx_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(D_PROBE, "Initializing controls"); + + gspca_dev->vdev.ctrl_handler = &gspca_dev->ctrl_handler; + return sd->sensor->init_controls(sd); +} + /* Start the camera */ static int stv06xx_start(struct gspca_dev *gspca_dev) { @@ -512,6 +523,7 @@ static const struct sd_desc sd_desc = { .name = MODULE_NAME, .config = stv06xx_config, .init = stv06xx_init, + .init_controls = stv06xx_init_controls, .start = stv06xx_start, .stopN = stv06xx_stopN, .pkt_scan = stv06xx_pkt_scan, @@ -530,9 +542,8 @@ static int stv06xx_config(struct gspca_dev *gspca_dev, PDEBUG(D_PROBE, "Configuring camera"); - sd->desc = sd_desc; sd->bridge = id->driver_info; - gspca_dev->sd_desc = &sd->desc; + gspca_dev->sd_desc = &sd_desc; if (dump_bridge) stv06xx_dump_bridge(sd); @@ -594,11 +605,12 @@ static void sd_disconnect(struct usb_interface *intf) { struct gspca_dev *gspca_dev = usb_get_intfdata(intf); struct sd *sd = (struct sd *) gspca_dev; + void *priv = sd->sensor_priv; PDEBUG(D_PROBE, "Disconnecting the stv06xx device"); - if (sd->sensor->disconnect) - sd->sensor->disconnect(sd); + sd->sensor = NULL; gspca_disconnect(intf); + kfree(priv); } static struct usb_driver sd_driver = { @@ -609,6 +621,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h index d270a5981af..34957a4ec15 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx.h @@ -89,9 +89,6 @@ struct sd { /* A pointer to the currently connected sensor */ const struct stv06xx_sensor *sensor; - /* A pointer to the sd_desc struct */ - struct sd_desc desc; - /* Sensor private data */ void *sensor_priv; diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c index a8698b7a756..06fa54c5efb 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c @@ -32,36 +32,6 @@ #include "stv06xx_hdcs.h" -static const struct ctrl hdcs1x00_ctrl[] = { - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = HDCS_DEFAULT_EXPOSURE, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = hdcs_set_exposure, - .get = hdcs_get_exposure - }, { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = HDCS_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = hdcs_set_gain, - .get = hdcs_get_gain - } -}; - static struct v4l2_pix_format hdcs1x00_mode[] = { { HDCS_1X00_DEF_WIDTH, @@ -76,36 +46,6 @@ static struct v4l2_pix_format hdcs1x00_mode[] = { } }; -static const struct ctrl hdcs1020_ctrl[] = { - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0x00, - .maximum = 0xffff, - .step = 0x1, - .default_value = HDCS_DEFAULT_EXPOSURE, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = hdcs_set_exposure, - .get = hdcs_get_exposure - }, { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "gain", - .minimum = 0x00, - .maximum = 0xff, - .step = 0x1, - .default_value = HDCS_DEFAULT_GAIN, - .flags = V4L2_CTRL_FLAG_SLIDER - }, - .set = hdcs_set_gain, - .get = hdcs_get_gain - } -}; - static struct v4l2_pix_format hdcs1020_mode[] = { { HDCS_1020_DEF_WIDTH, @@ -150,7 +90,6 @@ struct hdcs { } exp; int psmp; - u8 exp_cache, gain_cache; }; static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len) @@ -232,16 +171,6 @@ static int hdcs_reset(struct sd *sd) return err; } -static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct hdcs *hdcs = sd->sensor_priv; - - *val = hdcs->exp_cache; - - return 0; -} - static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -260,9 +189,6 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val) int cycles, err; u8 exp[14]; - val &= 0xff; - hdcs->exp_cache = val; - cycles = val * HDCS_CLK_FREQ_MHZ * 257; ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2); @@ -336,12 +262,9 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val) static int hdcs_set_gains(struct sd *sd, u8 g) { - struct hdcs *hdcs = sd->sensor_priv; int err; u8 gains[4]; - hdcs->gain_cache = g; - /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */ if (g > 127) g = 0x80 | (g / 2); @@ -352,17 +275,7 @@ static int hdcs_set_gains(struct sd *sd, u8 g) gains[3] = g; err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4); - return err; -} - -static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - struct hdcs *hdcs = sd->sensor_priv; - - *val = hdcs->gain_cache; - - return 0; + return err; } static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val) @@ -420,6 +333,39 @@ static int hdcs_set_size(struct sd *sd, return err; } +static int hdcs_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + int err = -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_GAIN: + err = hdcs_set_gain(gspca_dev, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + err = hdcs_set_exposure(gspca_dev, ctrl->val); + break; + } + return err; +} + +static const struct v4l2_ctrl_ops hdcs_ctrl_ops = { + .s_ctrl = hdcs_s_ctrl, +}; + +static int hdcs_init_controls(struct sd *sd) +{ + struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; + + v4l2_ctrl_handler_init(hdl, 2); + v4l2_ctrl_new_std(hdl, &hdcs_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 0xff, 1, HDCS_DEFAULT_EXPOSURE); + v4l2_ctrl_new_std(hdl, &hdcs_ctrl_ops, + V4L2_CID_GAIN, 0, 0xff, 1, HDCS_DEFAULT_GAIN); + return hdl->error; +} + static int hdcs_probe_1x00(struct sd *sd) { struct hdcs *hdcs; @@ -434,8 +380,6 @@ static int hdcs_probe_1x00(struct sd *sd) sd->gspca_dev.cam.cam_mode = hdcs1x00_mode; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1x00_mode); - sd->desc.ctrls = hdcs1x00_ctrl; - sd->desc.nctrls = ARRAY_SIZE(hdcs1x00_ctrl); hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); if (!hdcs) @@ -493,8 +437,6 @@ static int hdcs_probe_1020(struct sd *sd) sd->gspca_dev.cam.cam_mode = hdcs1020_mode; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(hdcs1020_mode); - sd->desc.ctrls = hdcs1020_ctrl; - sd->desc.nctrls = ARRAY_SIZE(hdcs1020_ctrl); hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); if (!hdcs) @@ -537,12 +479,6 @@ static int hdcs_stop(struct sd *sd) return hdcs_set_state(sd, HDCS_STATE_SLEEP); } -static void hdcs_disconnect(struct sd *sd) -{ - PDEBUG(D_PROBE, "Disconnecting the sensor"); - kfree(sd->sensor_priv); -} - static int hdcs_init(struct sd *sd) { struct hdcs *hdcs = sd->sensor_priv; @@ -587,16 +523,7 @@ static int hdcs_init(struct sd *sd) if (err < 0) return err; - err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN); - if (err < 0) - return err; - - err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height); - if (err < 0) - return err; - - err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE); - return err; + return hdcs_set_size(sd, hdcs->array.width, hdcs->array.height); } static int hdcs_dump(struct sd *sd) diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h index a14a84a5079..1ba9158d010 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h @@ -131,14 +131,12 @@ static int hdcs_probe_1x00(struct sd *sd); static int hdcs_probe_1020(struct sd *sd); static int hdcs_start(struct sd *sd); static int hdcs_init(struct sd *sd); +static int hdcs_init_controls(struct sd *sd); static int hdcs_stop(struct sd *sd); static int hdcs_dump(struct sd *sd); -static void hdcs_disconnect(struct sd *sd); -static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val); static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val); const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = { .name = "HP HDCS-1000/1100", @@ -152,10 +150,10 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = { .max_packet_size = { 847 }, .init = hdcs_init, + .init_controls = hdcs_init_controls, .probe = hdcs_probe_1x00, .start = hdcs_start, .stop = hdcs_stop, - .disconnect = hdcs_disconnect, .dump = hdcs_dump, }; @@ -171,6 +169,7 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = { .max_packet_size = { 847 }, .init = hdcs_init, + .init_controls = hdcs_init_controls, .probe = hdcs_probe_1020, .start = hdcs_start, .stop = hdcs_stop, diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c index 26f14fc4a13..cdfc3d05ab6 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c @@ -48,105 +48,16 @@ #include "stv06xx_pb0100.h" -static const struct ctrl pb0100_ctrl[] = { -#define GAIN_IDX 0 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128 - }, - .set = pb0100_set_gain, - .get = pb0100_get_gain - }, -#define RED_BALANCE_IDX 1 - { - { - .id = V4L2_CID_RED_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Red Balance", - .minimum = -255, - .maximum = 255, - .step = 1, - .default_value = 0 - }, - .set = pb0100_set_red_balance, - .get = pb0100_get_red_balance - }, -#define BLUE_BALANCE_IDX 2 - { - { - .id = V4L2_CID_BLUE_BALANCE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Blue Balance", - .minimum = -255, - .maximum = 255, - .step = 1, - .default_value = 0 - }, - .set = pb0100_set_blue_balance, - .get = pb0100_get_blue_balance - }, -#define EXPOSURE_IDX 3 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, - .maximum = 511, - .step = 1, - .default_value = 12 - }, - .set = pb0100_set_exposure, - .get = pb0100_get_exposure - }, -#define AUTOGAIN_IDX 4 - { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Automatic Gain and Exposure", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = pb0100_set_autogain, - .get = pb0100_get_autogain - }, -#define AUTOGAIN_TARGET_IDX 5 - { - { - .id = V4L2_CTRL_CLASS_USER + 0x1000, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Automatic Gain Target", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128 - }, - .set = pb0100_set_autogain_target, - .get = pb0100_get_autogain_target - }, -#define NATURAL_IDX 6 - { - { - .id = V4L2_CTRL_CLASS_USER + 0x1001, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Natural Light Source", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1 - }, - .set = pb0100_set_natural, - .get = pb0100_get_natural - } +struct pb0100_ctrls { + struct { /* one big happy control cluster... */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + struct v4l2_ctrl *exposure; + struct v4l2_ctrl *red; + struct v4l2_ctrl *blue; + struct v4l2_ctrl *natural; + }; + struct v4l2_ctrl *target; }; static struct v4l2_pix_format pb0100_mode[] = { @@ -174,38 +85,104 @@ static struct v4l2_pix_format pb0100_mode[] = { } }; +static int pb0100_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + struct pb0100_ctrls *ctrls = sd->sensor_priv; + int err = -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + err = pb0100_set_autogain(gspca_dev, ctrl->val); + if (err) + break; + if (ctrl->val) + break; + err = pb0100_set_gain(gspca_dev, ctrls->gain->val); + if (err) + break; + err = pb0100_set_exposure(gspca_dev, ctrls->exposure->val); + break; + case V4L2_CTRL_CLASS_USER + 0x1001: + err = pb0100_set_autogain_target(gspca_dev, ctrl->val); + break; + } + return err; +} + +static const struct v4l2_ctrl_ops pb0100_ctrl_ops = { + .s_ctrl = pb0100_s_ctrl, +}; + +static int pb0100_init_controls(struct sd *sd) +{ + struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; + struct pb0100_ctrls *ctrls; + static const struct v4l2_ctrl_config autogain_target = { + .ops = &pb0100_ctrl_ops, + .id = V4L2_CTRL_CLASS_USER + 0x1000, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Automatic Gain Target", + .max = 255, + .step = 1, + .def = 128, + }; + static const struct v4l2_ctrl_config natural_light = { + .ops = &pb0100_ctrl_ops, + .id = V4L2_CTRL_CLASS_USER + 0x1001, + .type = V4L2_CTRL_TYPE_BOOLEAN, + .name = "Natural Light Source", + .max = 1, + .step = 1, + .def = 1, + }; + + ctrls = kzalloc(sizeof(*ctrls), GFP_KERNEL); + if (!ctrls) + return -ENOMEM; + + v4l2_ctrl_handler_init(hdl, 6); + ctrls->autogain = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + ctrls->exposure = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 511, 1, 12); + ctrls->gain = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops, + V4L2_CID_GAIN, 0, 255, 1, 128); + ctrls->red = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops, + V4L2_CID_RED_BALANCE, -255, 255, 1, 0); + ctrls->blue = v4l2_ctrl_new_std(hdl, &pb0100_ctrl_ops, + V4L2_CID_BLUE_BALANCE, -255, 255, 1, 0); + ctrls->natural = v4l2_ctrl_new_custom(hdl, &natural_light, NULL); + ctrls->target = v4l2_ctrl_new_custom(hdl, &autogain_target, NULL); + if (hdl->error) { + kfree(ctrls); + return hdl->error; + } + sd->sensor_priv = ctrls; + v4l2_ctrl_auto_cluster(5, &ctrls->autogain, 0, false); + return 0; +} + static int pb0100_probe(struct sd *sd) { u16 sensor; - int i, err; - s32 *sensor_settings; + int err; err = stv06xx_read_sensor(sd, PB_IDENT, &sensor); if (err < 0) return -ENODEV; + if ((sensor >> 8) != 0x64) + return -ENODEV; - if ((sensor >> 8) == 0x64) { - sensor_settings = kmalloc( - ARRAY_SIZE(pb0100_ctrl) * sizeof(s32), - GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - - pr_info("Photobit pb0100 sensor detected\n"); - - sd->gspca_dev.cam.cam_mode = pb0100_mode; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode); - sd->desc.ctrls = pb0100_ctrl; - sd->desc.nctrls = ARRAY_SIZE(pb0100_ctrl); - for (i = 0; i < sd->desc.nctrls; i++) - sensor_settings[i] = pb0100_ctrl[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; + pr_info("Photobit pb0100 sensor detected\n"); - return 0; - } + sd->gspca_dev.cam.cam_mode = pb0100_mode; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(pb0100_mode); - return -ENODEV; + return 0; } static int pb0100_start(struct sd *sd) @@ -214,7 +191,6 @@ static int pb0100_start(struct sd *sd) struct usb_host_interface *alt; struct usb_interface *intf; struct cam *cam = &sd->gspca_dev.cam; - s32 *sensor_settings = sd->sensor_priv; u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv; intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface); @@ -255,13 +231,6 @@ static int pb0100_start(struct sd *sd) stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); } - /* set_gain also sets red and blue balance */ - pb0100_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); - pb0100_set_exposure(&sd->gspca_dev, sensor_settings[EXPOSURE_IDX]); - pb0100_set_autogain_target(&sd->gspca_dev, - sensor_settings[AUTOGAIN_TARGET_IDX]); - pb0100_set_autogain(&sd->gspca_dev, sensor_settings[AUTOGAIN_IDX]); - err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)|BIT(1)); PDEBUG(D_STREAM, "Started stream, status: %d", err); @@ -285,12 +254,6 @@ out: return (err < 0) ? err : 0; } -static void pb0100_disconnect(struct sd *sd) -{ - sd->sensor = NULL; - kfree(sd->sensor_priv); -} - /* FIXME: Sort the init commands out and put them into tables, this is only for getting the camera to work */ /* FIXME: No error handling for now, @@ -362,62 +325,32 @@ static int pb0100_dump(struct sd *sd) return 0; } -static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - - return 0; -} - static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val) { int err; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; + struct pb0100_ctrls *ctrls = sd->sensor_priv; - if (sensor_settings[AUTOGAIN_IDX]) - return -EBUSY; - - sensor_settings[GAIN_IDX] = val; err = stv06xx_write_sensor(sd, PB_G1GAIN, val); if (!err) err = stv06xx_write_sensor(sd, PB_G2GAIN, val); PDEBUG(D_V4L2, "Set green gain to %d, status: %d", val, err); if (!err) - err = pb0100_set_red_balance(gspca_dev, - sensor_settings[RED_BALANCE_IDX]); + err = pb0100_set_red_balance(gspca_dev, ctrls->red->val); if (!err) - err = pb0100_set_blue_balance(gspca_dev, - sensor_settings[BLUE_BALANCE_IDX]); + err = pb0100_set_blue_balance(gspca_dev, ctrls->blue->val); return err; } -static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[RED_BALANCE_IDX]; - - return 0; -} - static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) { int err; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; + struct pb0100_ctrls *ctrls = sd->sensor_priv; - if (sensor_settings[AUTOGAIN_IDX]) - return -EBUSY; - - sensor_settings[RED_BALANCE_IDX] = val; - val += sensor_settings[GAIN_IDX]; + val += ctrls->gain->val; if (val < 0) val = 0; else if (val > 255) @@ -429,27 +362,13 @@ static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[BLUE_BALANCE_IDX]; - - return 0; -} - static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) { int err; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; + struct pb0100_ctrls *ctrls = sd->sensor_priv; - if (sensor_settings[AUTOGAIN_IDX]) - return -EBUSY; - - sensor_settings[BLUE_BALANCE_IDX] = val; - val += sensor_settings[GAIN_IDX]; + val += ctrls->gain->val; if (val < 0) val = 0; else if (val > 255) @@ -461,51 +380,25 @@ static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) return err; } -static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[EXPOSURE_IDX]; - - return 0; -} - static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val) { - int err; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - if (sensor_settings[AUTOGAIN_IDX]) - return -EBUSY; + int err; - sensor_settings[EXPOSURE_IDX] = val; err = stv06xx_write_sensor(sd, PB_RINTTIME, val); PDEBUG(D_V4L2, "Set exposure to %d, status: %d", val, err); return err; } -static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTOGAIN_IDX]; - - return 0; -} - static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val) { int err; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; + struct pb0100_ctrls *ctrls = sd->sensor_priv; - sensor_settings[AUTOGAIN_IDX] = val; - if (sensor_settings[AUTOGAIN_IDX]) { - if (sensor_settings[NATURAL_IDX]) + if (val) { + if (ctrls->natural->val) val = BIT(6)|BIT(4)|BIT(0); else val = BIT(4)|BIT(0); @@ -514,29 +407,15 @@ static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val) err = stv06xx_write_sensor(sd, PB_EXPGAIN, val); PDEBUG(D_V4L2, "Set autogain to %d (natural: %d), status: %d", - sensor_settings[AUTOGAIN_IDX], sensor_settings[NATURAL_IDX], - err); + val, ctrls->natural->val, err); return err; } -static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[AUTOGAIN_TARGET_IDX]; - - return 0; -} - static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val) { int err, totalpixels, brightpixels, darkpixels; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[AUTOGAIN_TARGET_IDX] = val; /* Number of pixels counted by the sensor when subsampling the pixels. * Slightly larger than the real value to avoid oscillation */ @@ -553,23 +432,3 @@ static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val) return err; } - -static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[NATURAL_IDX]; - - return 0; -} - -static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - sensor_settings[NATURAL_IDX] = val; - - return pb0100_set_autogain(gspca_dev, sensor_settings[AUTOGAIN_IDX]); -} diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h index 757de246dc7..5071e5353fd 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h @@ -112,25 +112,17 @@ static int pb0100_probe(struct sd *sd); static int pb0100_start(struct sd *sd); static int pb0100_init(struct sd *sd); +static int pb0100_init_controls(struct sd *sd); static int pb0100_stop(struct sd *sd); static int pb0100_dump(struct sd *sd); -static void pb0100_disconnect(struct sd *sd); /* V4L2 controls supported by the driver */ -static int pb0100_get_gain(struct gspca_dev *gspca_dev, __s32 *val); static int pb0100_set_gain(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); static int pb0100_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); static int pb0100_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); static int pb0100_set_exposure(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_autogain(struct gspca_dev *gspca_dev, __s32 *val); static int pb0100_set_autogain(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_autogain_target(struct gspca_dev *gspca_dev, __s32 *val); static int pb0100_set_autogain_target(struct gspca_dev *gspca_dev, __s32 val); -static int pb0100_get_natural(struct gspca_dev *gspca_dev, __s32 *val); -static int pb0100_set_natural(struct gspca_dev *gspca_dev, __s32 val); const struct stv06xx_sensor stv06xx_sensor_pb0100 = { .name = "PB-0100", @@ -142,11 +134,11 @@ const struct stv06xx_sensor stv06xx_sensor_pb0100 = { .max_packet_size = { 847, 923 }, .init = pb0100_init, + .init_controls = pb0100_init_controls, .probe = pb0100_probe, .start = pb0100_start, .stop = pb0100_stop, .dump = pb0100_dump, - .disconnect = pb0100_disconnect, }; #endif diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h index fb229d8ded5..3a498c2495c 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h @@ -63,8 +63,8 @@ struct stv06xx_sensor { /* Performs a initialization sequence */ int (*init)(struct sd *sd); - /* Executed at device disconnect */ - void (*disconnect)(struct sd *sd); + /* Initializes the controls */ + int (*init_controls)(struct sd *sd); /* Reads a sensor register */ int (*read_sensor)(struct sd *sd, const u8 address, diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c index 9940e035b3a..8a57990dfe0 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c @@ -30,20 +30,6 @@ #include "stv06xx_st6422.h" -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - GAIN, - EXPOSURE, - NCTRLS /* number of controls */ -}; - -/* sensor settings */ -struct st6422_settings { - struct gspca_ctrl ctrls[NCTRLS]; -}; - static struct v4l2_pix_format st6422_mode[] = { /* Note we actually get 124 lines of data, of which we skip the 4st 4 as they are garbage */ @@ -74,83 +60,70 @@ static struct v4l2_pix_format st6422_mode[] = { }; /* V4L2 controls supported by the driver */ -static void st6422_set_brightness(struct gspca_dev *gspca_dev); -static void st6422_set_contrast(struct gspca_dev *gspca_dev); -static void st6422_set_gain(struct gspca_dev *gspca_dev); -static void st6422_set_exposure(struct gspca_dev *gspca_dev); - -static const struct ctrl st6422_ctrl[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 31, - .step = 1, - .default_value = 3 - }, - .set_control = st6422_set_brightness - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = 11 - }, - .set_control = st6422_set_contrast - }, -[GAIN] = { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gain", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 64 - }, - .set_control = st6422_set_gain - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0, -#define EXPOSURE_MAX 1023 - .maximum = EXPOSURE_MAX, - .step = 1, - .default_value = 256 - }, - .set_control = st6422_set_exposure - }, +static int setbrightness(struct sd *sd, s32 val); +static int setcontrast(struct sd *sd, s32 val); +static int setgain(struct sd *sd, u8 gain); +static int setexposure(struct sd *sd, s16 expo); + +static int st6422_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + int err = -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + err = setbrightness(sd, ctrl->val); + break; + case V4L2_CID_CONTRAST: + err = setcontrast(sd, ctrl->val); + break; + case V4L2_CID_GAIN: + err = setgain(sd, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + err = setexposure(sd, ctrl->val); + break; + } + + /* commit settings */ + if (err >= 0) + err = stv06xx_write_bridge(sd, 0x143f, 0x01); + sd->gspca_dev.usb_err = err; + return err; +} + +static const struct v4l2_ctrl_ops st6422_ctrl_ops = { + .s_ctrl = st6422_s_ctrl, }; -static int st6422_probe(struct sd *sd) +static int st6422_init_controls(struct sd *sd) { - struct st6422_settings *sensor_settings; + struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; + + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 31, 1, 3); + v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops, + V4L2_CID_CONTRAST, 0, 15, 1, 11); + v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 1023, 1, 256); + v4l2_ctrl_new_std(hdl, &st6422_ctrl_ops, + V4L2_CID_GAIN, 0, 255, 1, 64); + + return hdl->error; +} +static int st6422_probe(struct sd *sd) +{ if (sd->bridge != BRIDGE_ST6422) return -ENODEV; pr_info("st6422 sensor detected\n"); - sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; - sd->gspca_dev.cam.cam_mode = st6422_mode; sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode); - sd->gspca_dev.cam.ctrls = sensor_settings->ctrls; - sd->desc.ctrls = st6422_ctrl; - sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl); - sd->sensor_priv = sensor_settings; - return 0; } @@ -239,38 +212,22 @@ static int st6422_init(struct sd *sd) return err; } -static void st6422_disconnect(struct sd *sd) -{ - sd->sensor = NULL; - kfree(sd->sensor_priv); -} - -static int setbrightness(struct sd *sd) +static int setbrightness(struct sd *sd, s32 val) { - struct st6422_settings *sensor_settings = sd->sensor_priv; - /* val goes from 0 -> 31 */ - return stv06xx_write_bridge(sd, 0x1432, - sensor_settings->ctrls[BRIGHTNESS].val); + return stv06xx_write_bridge(sd, 0x1432, val); } -static int setcontrast(struct sd *sd) +static int setcontrast(struct sd *sd, s32 val) { - struct st6422_settings *sensor_settings = sd->sensor_priv; - /* Val goes from 0 -> 15 */ - return stv06xx_write_bridge(sd, 0x143a, - sensor_settings->ctrls[CONTRAST].val | 0xf0); + return stv06xx_write_bridge(sd, 0x143a, val | 0xf0); } -static int setgain(struct sd *sd) +static int setgain(struct sd *sd, u8 gain) { - struct st6422_settings *sensor_settings = sd->sensor_priv; - u8 gain; int err; - gain = sensor_settings->ctrls[GAIN].val; - /* Set red, green, blue, gain */ err = stv06xx_write_bridge(sd, 0x0509, gain); if (err < 0) @@ -292,13 +249,10 @@ static int setgain(struct sd *sd) return stv06xx_write_bridge(sd, 0x050d, 0x01); } -static int setexposure(struct sd *sd) +static int setexposure(struct sd *sd, s16 expo) { - struct st6422_settings *sensor_settings = sd->sensor_priv; - u16 expo; int err; - expo = sensor_settings->ctrls[EXPOSURE].val; err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff); if (err < 0) return err; @@ -318,22 +272,6 @@ static int st6422_start(struct sd *sd) if (err < 0) return err; - err = setbrightness(sd); - if (err < 0) - return err; - - err = setcontrast(sd); - if (err < 0) - return err; - - err = setexposure(sd); - if (err < 0) - return err; - - err = setgain(sd); - if (err < 0) - return err; - /* commit settings */ err = stv06xx_write_bridge(sd, 0x143f, 0x01); return (err < 0) ? err : 0; @@ -345,59 +283,3 @@ static int st6422_stop(struct sd *sd) return 0; } - -static void st6422_set_brightness(struct gspca_dev *gspca_dev) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - - err = setbrightness(sd); - - /* commit settings */ - if (err >= 0) - err = stv06xx_write_bridge(sd, 0x143f, 0x01); - - gspca_dev->usb_err = err; -} - -static void st6422_set_contrast(struct gspca_dev *gspca_dev) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - - err = setcontrast(sd); - - /* commit settings */ - if (err >= 0) - err = stv06xx_write_bridge(sd, 0x143f, 0x01); - - gspca_dev->usb_err = err; -} - -static void st6422_set_gain(struct gspca_dev *gspca_dev) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - - err = setgain(sd); - - /* commit settings */ - if (err >= 0) - err = stv06xx_write_bridge(sd, 0x143f, 0x01); - - gspca_dev->usb_err = err; -} - -static void st6422_set_exposure(struct gspca_dev *gspca_dev) -{ - int err; - struct sd *sd = (struct sd *) gspca_dev; - - err = setexposure(sd); - - /* commit settings */ - if (err >= 0) - err = stv06xx_write_bridge(sd, 0x143f, 0x01); - - gspca_dev->usb_err = err; -} diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h index d7498e06432..8f20fbf30f3 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h @@ -34,8 +34,8 @@ static int st6422_probe(struct sd *sd); static int st6422_start(struct sd *sd); static int st6422_init(struct sd *sd); +static int st6422_init_controls(struct sd *sd); static int st6422_stop(struct sd *sd); -static void st6422_disconnect(struct sd *sd); const struct stv06xx_sensor stv06xx_sensor_st6422 = { .name = "ST6422", @@ -43,10 +43,10 @@ const struct stv06xx_sensor stv06xx_sensor_st6422 = { .min_packet_size = { 300, 847 }, .max_packet_size = { 300, 847 }, .init = st6422_init, + .init_controls = st6422_init_controls, .probe = st6422_probe, .start = st6422_start, .stop = st6422_stop, - .disconnect = st6422_disconnect, }; #endif diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c index a5c69d9ebdd..748e1421d6d 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c @@ -44,130 +44,83 @@ static struct v4l2_pix_format vv6410_mode[] = { } }; -static const struct ctrl vv6410_ctrl[] = { -#define HFLIP_IDX 0 - { - { - .id = V4L2_CID_HFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "horizontal flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = vv6410_set_hflip, - .get = vv6410_get_hflip - }, -#define VFLIP_IDX 1 - { - { - .id = V4L2_CID_VFLIP, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "vertical flip", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0 - }, - .set = vv6410_set_vflip, - .get = vv6410_get_vflip - }, -#define GAIN_IDX 2 - { - { - .id = V4L2_CID_GAIN, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "analog gain", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = 10 - }, - .set = vv6410_set_analog_gain, - .get = vv6410_get_analog_gain - }, -#define EXPOSURE_IDX 3 - { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "exposure", - .minimum = 0, - .maximum = 32768, - .step = 1, - .default_value = 20000 - }, - .set = vv6410_set_exposure, - .get = vv6410_get_exposure +static int vv6410_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + int err = -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + err = vv6410_set_hflip(gspca_dev, ctrl->val); + break; + case V4L2_CID_VFLIP: + err = vv6410_set_vflip(gspca_dev, ctrl->val); + break; + case V4L2_CID_GAIN: + err = vv6410_set_analog_gain(gspca_dev, ctrl->val); + break; + case V4L2_CID_EXPOSURE: + err = vv6410_set_exposure(gspca_dev, ctrl->val); + break; } - }; + return err; +} + +static const struct v4l2_ctrl_ops vv6410_ctrl_ops = { + .s_ctrl = vv6410_s_ctrl, +}; static int vv6410_probe(struct sd *sd) { u16 data; - int err, i; - s32 *sensor_settings; + int err; err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data); if (err < 0) return -ENODEV; - if (data == 0x19) { - pr_info("vv6410 sensor detected\n"); + if (data != 0x19) + return -ENODEV; - sensor_settings = kmalloc(ARRAY_SIZE(vv6410_ctrl) * sizeof(s32), - GFP_KERNEL); - if (!sensor_settings) - return -ENOMEM; + pr_info("vv6410 sensor detected\n"); - sd->gspca_dev.cam.cam_mode = vv6410_mode; - sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode); - sd->desc.ctrls = vv6410_ctrl; - sd->desc.nctrls = ARRAY_SIZE(vv6410_ctrl); + sd->gspca_dev.cam.cam_mode = vv6410_mode; + sd->gspca_dev.cam.nmodes = ARRAY_SIZE(vv6410_mode); + return 0; +} - for (i = 0; i < sd->desc.nctrls; i++) - sensor_settings[i] = vv6410_ctrl[i].qctrl.default_value; - sd->sensor_priv = sensor_settings; - return 0; - } - return -ENODEV; +static int vv6410_init_controls(struct sd *sd) +{ + struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; + + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, + V4L2_CID_EXPOSURE, 0, 32768, 1, 20000); + v4l2_ctrl_new_std(hdl, &vv6410_ctrl_ops, + V4L2_CID_GAIN, 0, 15, 1, 10); + return hdl->error; } static int vv6410_init(struct sd *sd) { int err = 0, i; - s32 *sensor_settings = sd->sensor_priv; - for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) { + for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) stv06xx_write_bridge(sd, stv_bridge_init[i].addr, stv_bridge_init[i].data); - } if (err < 0) return err; err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init, ARRAY_SIZE(vv6410_sensor_init)); - if (err < 0) - return err; - - err = vv6410_set_exposure(&sd->gspca_dev, - sensor_settings[EXPOSURE_IDX]); - if (err < 0) - return err; - - err = vv6410_set_analog_gain(&sd->gspca_dev, - sensor_settings[GAIN_IDX]); - return (err < 0) ? err : 0; } -static void vv6410_disconnect(struct sd *sd) -{ - sd->sensor = NULL; - kfree(sd->sensor_priv); -} - static int vv6410_start(struct sd *sd) { int err; @@ -233,25 +186,12 @@ static int vv6410_dump(struct sd *sd) return (err < 0) ? err : 0; } -static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[HFLIP_IDX]; - PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - - return 0; -} - static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val) { int err; u16 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - sensor_settings[HFLIP_IDX] = val; err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); if (err < 0) return err; @@ -267,25 +207,12 @@ static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val) return (err < 0) ? err : 0; } -static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[VFLIP_IDX]; - PDEBUG(D_V4L2, "Read vertical flip %d", *val); - - return 0; -} - static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val) { int err; u16 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - sensor_settings[VFLIP_IDX] = val; err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); if (err < 0) return err; @@ -301,52 +228,23 @@ static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val) return (err < 0) ? err : 0; } -static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[GAIN_IDX]; - - PDEBUG(D_V4L2, "Read analog gain %d", *val); - - return 0; -} - static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val) { int err; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - sensor_settings[GAIN_IDX] = val; PDEBUG(D_V4L2, "Set analog gain to %d", val); err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf)); return (err < 0) ? err : 0; } -static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) -{ - struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; - - *val = sensor_settings[EXPOSURE_IDX]; - - PDEBUG(D_V4L2, "Read exposure %d", *val); - - return 0; -} - static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val) { int err; struct sd *sd = (struct sd *) gspca_dev; - s32 *sensor_settings = sd->sensor_priv; unsigned int fine, coarse; - sensor_settings[EXPOSURE_IDX] = val; - val = (val * val >> 14) + val / 4; fine = val % VV6410_CIF_LINELENGTH; diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h index a25b8873f2e..53e67b40ca0 100644 --- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h +++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h @@ -178,18 +178,14 @@ static int vv6410_probe(struct sd *sd); static int vv6410_start(struct sd *sd); static int vv6410_init(struct sd *sd); +static int vv6410_init_controls(struct sd *sd); static int vv6410_stop(struct sd *sd); static int vv6410_dump(struct sd *sd); -static void vv6410_disconnect(struct sd *sd); /* V4L2 controls supported by the driver */ -static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); static int vv6410_set_hflip(struct gspca_dev *gspca_dev, __s32 val); -static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val); -static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val); static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val); -static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val); const struct stv06xx_sensor stv06xx_sensor_vv6410 = { @@ -202,11 +198,11 @@ const struct stv06xx_sensor stv06xx_sensor_vv6410 = { .min_packet_size = { 1023 }, .max_packet_size = { 1023 }, .init = vv6410_init, + .init_controls = vv6410_init_controls, .probe = vv6410_probe, .start = vv6410_start, .stop = vv6410_stop, .dump = vv6410_dump, - .disconnect = vv6410_disconnect, }; /* If NULL, only single value to write, stored in len */ diff --git a/drivers/media/video/gspca/topro.c b/drivers/media/video/gspca/topro.c index 444d3c5b907..c6326d177a3 100644 --- a/drivers/media/video/gspca/topro.c +++ b/drivers/media/video/gspca/topro.c @@ -4675,11 +4675,9 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* -- do autogain -- */ /* gain setting is done in setexposure() for tp6810 */ static void setgain(struct gspca_dev *gspca_dev) {} -/* !! coarse_grained_expo_autogain is not used !! */ -#define exp_too_low_cnt bridge -#define exp_too_high_cnt sensor - +#define WANT_REGULAR_AUTOGAIN #include "autogain_functions.h" + static void sd_dq_callback(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c index 911152e169d..15a30f7a4b2 100644 --- a/drivers/media/video/gspca/vicam.c +++ b/drivers/media/video/gspca/vicam.c @@ -37,9 +37,12 @@ #include <linux/ihex.h> #include "gspca.h" +#define VICAM_FIRMWARE "vicam/firmware.fw" + MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_DESCRIPTION("GSPCA ViCam USB Camera Driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(VICAM_FIRMWARE); enum e_ctrl { GAIN, @@ -222,7 +225,11 @@ static void vicam_dostream(struct work_struct *work) goto exit; } - while (gspca_dev->present && gspca_dev->streaming) { + while (gspca_dev->dev && gspca_dev->streaming) { +#ifdef CONFIG_PM + if (gspca_dev->frozen) + break; +#endif ret = vicam_read_frame(gspca_dev, buffer, frame_sz); if (ret < 0) break; @@ -268,7 +275,7 @@ static int sd_init(struct gspca_dev *gspca_dev) const struct firmware *uninitialized_var(fw); u8 *firmware_buf; - ret = request_ihex_firmware(&fw, "vicam/firmware.fw", + ret = request_ihex_firmware(&fw, VICAM_FIRMWARE, &gspca_dev->dev->dev); if (ret) { pr_err("Failed to load \"vicam/firmware.fw\": %d\n", ret); @@ -324,7 +331,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev) dev->work_thread = NULL; mutex_lock(&gspca_dev->usb_lock); - if (gspca_dev->present) + if (gspca_dev->dev) vicam_set_camera_power(gspca_dev, 0); } diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 7d9a4f1be9d..f0bacee33ef 100644 --- a/drivers/media/video/gspca/zc3xx.c +++ b/drivers/media/video/gspca/zc3xx.c @@ -32,29 +32,25 @@ MODULE_LICENSE("GPL"); static int force_sensor = -1; -#define REG08_DEF 3 /* default JPEG compression (70%) */ +#define REG08_DEF 3 /* default JPEG compression (75%) */ #include "zc3xx-reg.h" -/* controls */ -enum e_ctrl { - BRIGHTNESS, - CONTRAST, - EXPOSURE, - GAMMA, - AUTOGAIN, - LIGHTFREQ, - SHARPNESS, - QUALITY, - NCTRLS /* number of controls */ -}; - -#define AUTOGAIN_DEF 1 - /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - struct gspca_ctrl ctrls[NCTRLS]; + struct { /* gamma/brightness/contrast control cluster */ + struct v4l2_ctrl *gamma; + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *contrast; + }; + struct { /* autogain/exposure control cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *exposure; + }; + struct v4l2_ctrl *plfreq; + struct v4l2_ctrl *sharpness; + struct v4l2_ctrl *jpegqual; struct work_struct work; struct workqueue_struct *work_thread; @@ -94,114 +90,6 @@ enum sensors { SENSOR_MAX }; -/* V4L2 controls supported by the driver */ -static void setcontrast(struct gspca_dev *gspca_dev); -static void setexposure(struct gspca_dev *gspca_dev); -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val); -static void setlightfreq(struct gspca_dev *gspca_dev); -static void setsharpness(struct gspca_dev *gspca_dev); -static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val); - -static const struct ctrl sd_ctrls[NCTRLS] = { -[BRIGHTNESS] = { - { - .id = V4L2_CID_BRIGHTNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Brightness", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128, - }, - .set_control = setcontrast - }, -[CONTRAST] = { - { - .id = V4L2_CID_CONTRAST, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Contrast", - .minimum = 0, - .maximum = 255, - .step = 1, - .default_value = 128, - }, - .set_control = setcontrast - }, -[EXPOSURE] = { - { - .id = V4L2_CID_EXPOSURE, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Exposure", - .minimum = 0x30d, - .maximum = 0x493e, - .step = 1, - .default_value = 0x927 - }, - .set_control = setexposure - }, -[GAMMA] = { - { - .id = V4L2_CID_GAMMA, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Gamma", - .minimum = 1, - .maximum = 6, - .step = 1, - .default_value = 4, - }, - .set_control = setcontrast - }, -[AUTOGAIN] = { - { - .id = V4L2_CID_AUTOGAIN, - .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = AUTOGAIN_DEF, - .flags = V4L2_CTRL_FLAG_UPDATE - }, - .set = sd_setautogain - }, -[LIGHTFREQ] = { - { - .id = V4L2_CID_POWER_LINE_FREQUENCY, - .type = V4L2_CTRL_TYPE_MENU, - .name = "Light frequency filter", - .minimum = 0, - .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */ - .step = 1, - .default_value = 0, - }, - .set_control = setlightfreq - }, -[SHARPNESS] = { - { - .id = V4L2_CID_SHARPNESS, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Sharpness", - .minimum = 0, - .maximum = 3, - .step = 1, - .default_value = 2, - }, - .set_control = setsharpness - }, -[QUALITY] = { - { - .id = V4L2_CID_JPEG_COMPRESSION_QUALITY, - .type = V4L2_CTRL_TYPE_INTEGER, - .name = "Compression Quality", - .minimum = 40, - .maximum = 70, - .step = 1, - .default_value = 70 /* updated in sd_init() */ - }, - .set = sd_setquality - }, -}; - static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, @@ -241,8 +129,11 @@ static const struct v4l2_pix_format sif_mode[] = { .priv = 0}, }; -/* bridge reg08 -> JPEG quality conversion table */ -static u8 jpeg_qual[] = {40, 50, 60, 70, /*80*/}; +/* + * Bridge reg08 bits 1-2 -> JPEG quality conversion table. Note the highest + * quality setting is not usable as USB 1 does not have enough bandwidth. + */ +static u8 jpeg_qual[] = {50, 75, 87, /* 94 */}; /* usb exchanges */ struct usb_action { @@ -5818,10 +5709,8 @@ static void setmatrix(struct gspca_dev *gspca_dev) reg_w(gspca_dev, matrix[i], 0x010a + i); } -static void setsharpness(struct gspca_dev *gspca_dev) +static void setsharpness(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - int sharpness; static const u8 sharpness_tb[][2] = { {0x02, 0x03}, {0x04, 0x07}, @@ -5829,19 +5718,18 @@ static void setsharpness(struct gspca_dev *gspca_dev) {0x10, 0x1e} }; - sharpness = sd->ctrls[SHARPNESS].val; - reg_w(gspca_dev, sharpness_tb[sharpness][0], 0x01c6); + reg_w(gspca_dev, sharpness_tb[val][0], 0x01c6); reg_r(gspca_dev, 0x01c8); reg_r(gspca_dev, 0x01c9); reg_r(gspca_dev, 0x01ca); - reg_w(gspca_dev, sharpness_tb[sharpness][1], 0x01cb); + reg_w(gspca_dev, sharpness_tb[val][1], 0x01cb); } -static void setcontrast(struct gspca_dev *gspca_dev) +static void setcontrast(struct gspca_dev *gspca_dev, + s32 gamma, s32 brightness, s32 contrast) { - struct sd *sd = (struct sd *) gspca_dev; const u8 *Tgamma; - int g, i, brightness, contrast, adj, gp1, gp2; + int g, i, adj, gp1, gp2; u8 gr[16]; static const u8 delta_b[16] = /* delta for brightness */ {0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d, @@ -5864,10 +5752,10 @@ static void setcontrast(struct gspca_dev *gspca_dev) 0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff}, }; - Tgamma = gamma_tb[sd->ctrls[GAMMA].val - 1]; + Tgamma = gamma_tb[gamma - 1]; - contrast = ((int) sd->ctrls[CONTRAST].val - 128); /* -128 / 127 */ - brightness = ((int) sd->ctrls[BRIGHTNESS].val - 128); /* -128 / 92 */ + contrast -= 128; /* -128 / 127 */ + brightness -= 128; /* -128 / 92 */ adj = 0; gp1 = gp2 = 0; for (i = 0; i < 16; i++) { @@ -5894,25 +5782,15 @@ static void setcontrast(struct gspca_dev *gspca_dev) reg_w(gspca_dev, gr[i], 0x0130 + i); /* gradient */ } -static void getexposure(struct gspca_dev *gspca_dev) +static s32 getexposure(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - - if (sd->sensor != SENSOR_HV7131R) - return; - sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9) + return (i2c_read(gspca_dev, 0x25) << 9) | (i2c_read(gspca_dev, 0x26) << 1) | (i2c_read(gspca_dev, 0x27) >> 7); } -static void setexposure(struct gspca_dev *gspca_dev) +static void setexposure(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - int val; - - if (sd->sensor != SENSOR_HV7131R) - return; - val = sd->ctrls[EXPOSURE].val; i2c_write(gspca_dev, 0x25, val >> 9, 0x00); i2c_write(gspca_dev, 0x26, val >> 1, 0x00); i2c_write(gspca_dev, 0x27, val << 7, 0x00); @@ -5921,20 +5799,8 @@ static void setexposure(struct gspca_dev *gspca_dev) static void setquality(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - s8 reg07; - - reg07 = 0; - switch (sd->sensor) { - case SENSOR_OV7620: - reg07 = 0x30; - break; - case SENSOR_HV7131R: - case SENSOR_PAS202B: - return; /* done by work queue */ - } + jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08 >> 1]); reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING); - if (reg07 != 0) - reg_w(gspca_dev, reg07, 0x0007); } /* Matches the sensor's internal frame rate to the lighting frequency. @@ -5943,7 +5809,7 @@ static void setquality(struct gspca_dev *gspca_dev) * 60Hz, for American lighting * 0 = No Fliker (for outdoore usage) */ -static void setlightfreq(struct gspca_dev *gspca_dev) +static void setlightfreq(struct gspca_dev *gspca_dev, s32 val) { struct sd *sd = (struct sd *) gspca_dev; int i, mode; @@ -6027,7 +5893,7 @@ static void setlightfreq(struct gspca_dev *gspca_dev) tas5130c_60HZ, tas5130c_60HZScale}, }; - i = sd->ctrls[LIGHTFREQ].val * 2; + i = val * 2; mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; if (mode) i++; /* 320x240 */ @@ -6037,14 +5903,14 @@ static void setlightfreq(struct gspca_dev *gspca_dev) usb_exchange(gspca_dev, zc3_freq); switch (sd->sensor) { case SENSOR_GC0305: - if (mode /* if 320x240 */ - && sd->ctrls[LIGHTFREQ].val == 1) /* and 50Hz */ + if (mode /* if 320x240 */ + && val == 1) /* and 50Hz */ reg_w(gspca_dev, 0x85, 0x018d); /* win: 0x80, 0x018d */ break; case SENSOR_OV7620: - if (!mode) { /* if 640x480 */ - if (sd->ctrls[LIGHTFREQ].val != 0) /* and filter */ + if (!mode) { /* if 640x480 */ + if (val != 0) /* and filter */ reg_w(gspca_dev, 0x40, 0x0002); else reg_w(gspca_dev, 0x44, 0x0002); @@ -6056,22 +5922,15 @@ static void setlightfreq(struct gspca_dev *gspca_dev) } } -static void setautogain(struct gspca_dev *gspca_dev) +static void setautogain(struct gspca_dev *gspca_dev, s32 val) { - struct sd *sd = (struct sd *) gspca_dev; - u8 autoval; - - if (sd->ctrls[AUTOGAIN].val) - autoval = 0x42; - else - autoval = 0x02; - reg_w(gspca_dev, autoval, 0x0180); + reg_w(gspca_dev, val ? 0x42 : 0x02, 0x0180); } -/* update the transfer parameters */ -/* This function is executed from a work queue. */ -/* The exact use of the bridge registers 07 and 08 is not known. - * The following algorithm has been adapted from ms-win traces */ +/* + * Update the transfer parameters. + * This function is executed from a work queue. + */ static void transfer_update(struct work_struct *work) { struct sd *sd = container_of(work, struct sd, work); @@ -6079,96 +5938,55 @@ static void transfer_update(struct work_struct *work) int change, good; u8 reg07, reg11; - /* synchronize with the main driver and initialize the registers */ - mutex_lock(&gspca_dev->usb_lock); - reg07 = 0; /* max */ - reg_w(gspca_dev, reg07, 0x0007); - reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING); - mutex_unlock(&gspca_dev->usb_lock); + /* reg07 gets set to 0 by sd_start before starting us */ + reg07 = 0; good = 0; for (;;) { msleep(100); - /* get the transfer status */ - /* the bit 0 of the bridge register 11 indicates overflow */ mutex_lock(&gspca_dev->usb_lock); - if (!gspca_dev->present || !gspca_dev->streaming) +#ifdef CONFIG_PM + if (gspca_dev->frozen) goto err; +#endif + if (!gspca_dev->dev || !gspca_dev->streaming) + goto err; + + /* Bit 0 of register 11 indicates FIFO overflow */ + gspca_dev->usb_err = 0; reg11 = reg_r(gspca_dev, 0x0011); - if (gspca_dev->usb_err < 0 - || !gspca_dev->present || !gspca_dev->streaming) + if (gspca_dev->usb_err) goto err; change = reg11 & 0x01; if (change) { /* overflow */ - switch (reg07) { - case 0: /* max */ - reg07 = sd->sensor == SENSOR_HV7131R - ? 0x30 : 0x32; - if (sd->reg08 != 0) { - change = 3; - sd->reg08--; - } - break; - case 0x32: - reg07 -= 4; - break; - default: - reg07 -= 2; - break; - case 2: - change = 0; /* already min */ - break; - } good = 0; + + if (reg07 == 0) /* Bit Rate Control not enabled? */ + reg07 = 0x32; /* Allow 98 bytes / unit */ + else if (reg07 > 2) + reg07 -= 2; /* Decrease allowed bytes / unit */ + else + change = 0; } else { /* no overflow */ - if (reg07 != 0) { /* if not max */ - good++; - if (good >= 10) { - good = 0; + good++; + if (good >= 10) { + good = 0; + if (reg07) { /* BRC enabled? */ change = 1; - reg07 += 2; - switch (reg07) { - case 0x30: - if (sd->sensor == SENSOR_PAS202B) - reg07 += 2; - break; - case 0x32: - case 0x34: + if (reg07 < 0x32) + reg07 += 2; + else reg07 = 0; - break; - } - } - } else { /* reg07 max */ - if (sd->reg08 < sizeof jpeg_qual - 1) { - good++; - if (good > 10) { - sd->reg08++; - change = 2; - } } } } if (change) { - if (change & 1) { - reg_w(gspca_dev, reg07, 0x0007); - if (gspca_dev->usb_err < 0 - || !gspca_dev->present - || !gspca_dev->streaming) - goto err; - } - if (change & 2) { - reg_w(gspca_dev, sd->reg08, - ZC3XX_R008_CLOCKSETTING); - if (gspca_dev->usb_err < 0 - || !gspca_dev->present - || !gspca_dev->streaming) - goto err; - sd->ctrls[QUALITY].val = jpeg_qual[sd->reg08]; - jpeg_set_qual(sd->jpeg_hdr, - jpeg_qual[sd->reg08]); - } + gspca_dev->usb_err = 0; + reg_w(gspca_dev, reg07, 0x0007); + if (gspca_dev->usb_err) + goto err; } mutex_unlock(&gspca_dev->usb_lock); } @@ -6503,7 +6321,6 @@ static int sd_config(struct gspca_dev *gspca_dev, /* define some sensors from the vendor/product */ sd->sensor = id->driver_info; - gspca_dev->cam.ctrls = sd->ctrls; sd->reg08 = REG08_DEF; INIT_WORK(&sd->work, transfer_update); @@ -6511,12 +6328,87 @@ static int sd_config(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) +static int zcxx_g_volatile_ctrl(struct v4l2_ctrl *ctrl) { - struct sd *sd = (struct sd *) gspca_dev; - struct cam *cam; - int sensor; + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + gspca_dev->usb_err = 0; + if (ctrl->val && sd->exposure && gspca_dev->streaming) + sd->exposure->val = getexposure(gspca_dev); + return gspca_dev->usb_err; + } + return -EINVAL; +} + +static int zcxx_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct gspca_dev *gspca_dev = + container_of(ctrl->handler, struct gspca_dev, ctrl_handler); + struct sd *sd = (struct sd *)gspca_dev; + int i, qual; + + gspca_dev->usb_err = 0; + + if (ctrl->id == V4L2_CID_JPEG_COMPRESSION_QUALITY) { + qual = sd->reg08 >> 1; + + for (i = 0; i < ARRAY_SIZE(jpeg_qual); i++) { + if (ctrl->val <= jpeg_qual[i]) + break; + } + if (i > 0 && i == qual && ctrl->val < jpeg_qual[i]) + i--; + + /* With high quality settings we need max bandwidth */ + if (i >= 2 && gspca_dev->streaming && + !gspca_dev->cam.needs_full_bandwidth) + return -EBUSY; + + sd->reg08 = (i << 1) | 1; + ctrl->val = jpeg_qual[i]; + } + + if (!gspca_dev->streaming) + return 0; + + switch (ctrl->id) { + /* gamma/brightness/contrast cluster */ + case V4L2_CID_GAMMA: + setcontrast(gspca_dev, sd->gamma->val, + sd->brightness->val, sd->contrast->val); + break; + /* autogain/exposure cluster */ + case V4L2_CID_AUTOGAIN: + setautogain(gspca_dev, ctrl->val); + if (!gspca_dev->usb_err && !ctrl->val && sd->exposure) + setexposure(gspca_dev, sd->exposure->val); + break; + case V4L2_CID_POWER_LINE_FREQUENCY: + setlightfreq(gspca_dev, ctrl->val); + break; + case V4L2_CID_SHARPNESS: + setsharpness(gspca_dev, ctrl->val); + break; + case V4L2_CID_JPEG_COMPRESSION_QUALITY: + setquality(gspca_dev); + break; + } + return gspca_dev->usb_err; +} + +static const struct v4l2_ctrl_ops zcxx_ctrl_ops = { + .g_volatile_ctrl = zcxx_g_volatile_ctrl, + .s_ctrl = zcxx_s_ctrl, +}; + +static int sd_init_controls(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *)gspca_dev; + struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; static const u8 gamma[SENSOR_MAX] = { [SENSOR_ADCM2700] = 4, [SENSOR_CS2102] = 4, @@ -6538,6 +6430,48 @@ static int sd_init(struct gspca_dev *gspca_dev) [SENSOR_PO2030] = 4, [SENSOR_TAS5130C] = 3, }; + + gspca_dev->vdev.ctrl_handler = hdl; + v4l2_ctrl_handler_init(hdl, 8); + sd->brightness = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + sd->contrast = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 128); + sd->gamma = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops, + V4L2_CID_GAMMA, 1, 6, 1, gamma[sd->sensor]); + if (sd->sensor == SENSOR_HV7131R) + sd->exposure = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops, + V4L2_CID_EXPOSURE, 0x30d, 0x493e, 1, 0x927); + sd->autogain = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + if (sd->sensor != SENSOR_OV7630C) + sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &zcxx_ctrl_ops, + V4L2_CID_POWER_LINE_FREQUENCY, + V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, + V4L2_CID_POWER_LINE_FREQUENCY_DISABLED); + sd->sharpness = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops, + V4L2_CID_SHARPNESS, 0, 3, 1, + sd->sensor == SENSOR_PO2030 ? 0 : 2); + sd->jpegqual = v4l2_ctrl_new_std(hdl, &zcxx_ctrl_ops, + V4L2_CID_JPEG_COMPRESSION_QUALITY, + jpeg_qual[0], jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1], 1, + jpeg_qual[REG08_DEF >> 1]); + if (hdl->error) { + pr_err("Could not initialize controls\n"); + return hdl->error; + } + v4l2_ctrl_cluster(3, &sd->gamma); + if (sd->sensor == SENSOR_HV7131R) + v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, true); + return 0; +} + +/* 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 cam *cam; + int sensor; static const u8 mode_tb[SENSOR_MAX] = { [SENSOR_ADCM2700] = 2, [SENSOR_CS2102] = 1, @@ -6559,27 +6493,6 @@ static int sd_init(struct gspca_dev *gspca_dev) [SENSOR_PO2030] = 1, [SENSOR_TAS5130C] = 1, }; - static const u8 reg08_tb[SENSOR_MAX] = { - [SENSOR_ADCM2700] = 1, - [SENSOR_CS2102] = 3, - [SENSOR_CS2102K] = 3, - [SENSOR_GC0303] = 2, - [SENSOR_GC0305] = 3, - [SENSOR_HDCS2020] = 1, - [SENSOR_HV7131B] = 3, - [SENSOR_HV7131R] = 3, - [SENSOR_ICM105A] = 3, - [SENSOR_MC501CB] = 3, - [SENSOR_MT9V111_1] = 3, - [SENSOR_MT9V111_3] = 3, - [SENSOR_OV7620] = 1, - [SENSOR_OV7630C] = 3, - [SENSOR_PAS106] = 3, - [SENSOR_PAS202B] = 3, - [SENSOR_PB0330] = 3, - [SENSOR_PO2030] = 2, - [SENSOR_TAS5130C] = 3, - }; sensor = zcxx_probeSensor(gspca_dev); if (sensor >= 0) @@ -6688,7 +6601,6 @@ static int sd_init(struct gspca_dev *gspca_dev) case 0x2030: PDEBUG(D_PROBE, "Find Sensor PO2030"); sd->sensor = SENSOR_PO2030; - sd->ctrls[SHARPNESS].def = 0; /* from win traces */ break; case 0x7620: PDEBUG(D_PROBE, "Find Sensor OV7620"); @@ -6730,36 +6642,18 @@ static int sd_init(struct gspca_dev *gspca_dev) break; } - sd->ctrls[GAMMA].def = gamma[sd->sensor]; - sd->reg08 = reg08_tb[sd->sensor]; - sd->ctrls[QUALITY].def = jpeg_qual[sd->reg08]; - sd->ctrls[QUALITY].min = jpeg_qual[0]; - sd->ctrls[QUALITY].max = jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1]; - - switch (sd->sensor) { - case SENSOR_HV7131R: - gspca_dev->ctrl_dis = (1 << QUALITY); - break; - case SENSOR_OV7630C: - gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE); - break; - case SENSOR_PAS202B: - gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE); - break; - default: - gspca_dev->ctrl_dis = (1 << EXPOSURE); - break; - } -#if AUTOGAIN_DEF - if (sd->ctrls[AUTOGAIN].val) - gspca_dev->ctrl_inac = (1 << EXPOSURE); -#endif - /* switch off the led */ reg_w(gspca_dev, 0x01, 0x0000); return gspca_dev->usb_err; } +static int sd_pre_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + gspca_dev->cam.needs_full_bandwidth = (sd->reg08 >= 4) ? 1 : 0; + return 0; +} + static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -6864,7 +6758,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x03, 0x0008); break; } - setsharpness(gspca_dev); + setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness)); /* set the gamma tables when not set */ switch (sd->sensor) { @@ -6873,7 +6767,9 @@ static int sd_start(struct gspca_dev *gspca_dev) case SENSOR_OV7630C: break; default: - setcontrast(gspca_dev); + setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->gamma), + v4l2_ctrl_g_ctrl(sd->brightness), + v4l2_ctrl_g_ctrl(sd->contrast)); break; } setmatrix(gspca_dev); /* one more time? */ @@ -6885,8 +6781,10 @@ static int sd_start(struct gspca_dev *gspca_dev) break; } setquality(gspca_dev); - jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08]); - setlightfreq(gspca_dev); + /* Start with BRC disabled, transfer_update will enable it if needed */ + reg_w(gspca_dev, 0x00, 0x0007); + if (sd->plfreq) + setlightfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->plfreq)); switch (sd->sensor) { case SENSOR_ADCM2700: @@ -6897,7 +6795,7 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x40, 0x0117); break; case SENSOR_HV7131R: - setexposure(gspca_dev); + setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure)); reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN); break; case SENSOR_GC0305: @@ -6921,21 +6819,16 @@ static int sd_start(struct gspca_dev *gspca_dev) break; } - setautogain(gspca_dev); + setautogain(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain)); - /* start the transfer update thread if needed */ - if (gspca_dev->usb_err >= 0) { - switch (sd->sensor) { - case SENSOR_HV7131R: - case SENSOR_PAS202B: - sd->work_thread = - create_singlethread_workqueue(KBUILD_MODNAME); - queue_work(sd->work_thread, &sd->work); - break; - } - } + if (gspca_dev->usb_err < 0) + return gspca_dev->usb_err; - return gspca_dev->usb_err; + /* Start the transfer parameters update thread */ + sd->work_thread = create_singlethread_workqueue(KBUILD_MODNAME); + queue_work(sd->work_thread, &sd->work); + + return 0; } /* called on streamoff with alt 0 and on disconnect */ @@ -6949,7 +6842,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev) mutex_lock(&gspca_dev->usb_lock); sd->work_thread = NULL; } - if (!gspca_dev->present) + if (!gspca_dev->dev) return; send_unknown(gspca_dev, sd->sensor); } @@ -6987,72 +6880,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, gspca_frame_add(gspca_dev, INTER_PACKET, data, len); } -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - - sd->ctrls[AUTOGAIN].val = val; - if (val) { - gspca_dev->ctrl_inac |= (1 << EXPOSURE); - } else { - gspca_dev->ctrl_inac &= ~(1 << EXPOSURE); - if (gspca_dev->streaming) - getexposure(gspca_dev); - } - if (gspca_dev->streaming) - setautogain(gspca_dev); - return gspca_dev->usb_err; -} - -static int sd_querymenu(struct gspca_dev *gspca_dev, - struct v4l2_querymenu *menu) -{ - switch (menu->id) { - case V4L2_CID_POWER_LINE_FREQUENCY: - switch (menu->index) { - case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */ - strcpy((char *) menu->name, "NoFliker"); - return 0; - case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */ - strcpy((char *) menu->name, "50 Hz"); - return 0; - case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */ - strcpy((char *) menu->name, "60 Hz"); - return 0; - } - break; - } - return -EINVAL; -} - -static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val) -{ - struct sd *sd = (struct sd *) gspca_dev; - int i; - - for (i = 0; i < ARRAY_SIZE(jpeg_qual) - 1; i++) { - if (val <= jpeg_qual[i]) - break; - } - if (i > 0 - && i == sd->reg08 - && val < jpeg_qual[sd->reg08]) - i--; - sd->reg08 = i; - sd->ctrls[QUALITY].val = jpeg_qual[i]; - if (gspca_dev->streaming) - jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val); - return gspca_dev->usb_err; -} - static int sd_set_jcomp(struct gspca_dev *gspca_dev, struct v4l2_jpegcompression *jcomp) { struct sd *sd = (struct sd *) gspca_dev; + int ret; - sd_setquality(gspca_dev, jcomp->quality); - jcomp->quality = sd->ctrls[QUALITY].val; - return gspca_dev->usb_err; + ret = v4l2_ctrl_s_ctrl(sd->jpegqual, jcomp->quality); + if (ret) + return ret; + jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual); + return 0; } static int sd_get_jcomp(struct gspca_dev *gspca_dev, @@ -7061,7 +6899,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev, struct sd *sd = (struct sd *) gspca_dev; memset(jcomp, 0, sizeof *jcomp); - jcomp->quality = sd->ctrls[QUALITY].val; + jcomp->quality = v4l2_ctrl_g_ctrl(sd->jpegqual); jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT; return 0; @@ -7085,14 +6923,13 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, static const struct sd_desc sd_desc = { .name = KBUILD_MODNAME, - .ctrls = sd_ctrls, - .nctrls = ARRAY_SIZE(sd_ctrls), .config = sd_config, .init = sd_init, + .init_controls = sd_init_controls, + .isoc_init = sd_pre_start, .start = sd_start, .stop0 = sd_stop0, .pkt_scan = sd_pkt_scan, - .querymenu = sd_querymenu, .get_jcomp = sd_get_jcomp, .set_jcomp = sd_set_jcomp, #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) @@ -7176,6 +7013,7 @@ static struct usb_driver sd_driver = { #ifdef CONFIG_PM .suspend = gspca_suspend, .resume = gspca_resume, + .reset_resume = gspca_resume, #endif }; |