summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/gspca
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/gspca')
-rw-r--r--linux/drivers/media/video/gspca/gspca.c234
-rw-r--r--linux/drivers/media/video/gspca/gspca.h2
-rw-r--r--linux/drivers/media/video/gspca/pac207.c68
-rw-r--r--linux/drivers/media/video/gspca/sonixb.c351
-rw-r--r--linux/drivers/media/video/gspca/vc032x.c43
5 files changed, 475 insertions, 223 deletions
diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c
index 943c5981f..cb07f2b2e 100644
--- a/linux/drivers/media/video/gspca/gspca.c
+++ b/linux/drivers/media/video/gspca/gspca.c
@@ -42,8 +42,8 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 6)
-static const char version[] = "2.1.6";
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
static int video_nr = -1;
@@ -561,11 +561,6 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev)
gspca_set_alt0(gspca_dev);
gspca_dev->sd_desc->stop0(gspca_dev);
PDEBUG(D_STREAM, "stream off OK");
- } else {
- destroy_urbs(gspca_dev);
- atomic_inc(&gspca_dev->nevent);
- wake_up_interruptible(&gspca_dev->wq);
- PDEBUG(D_ERR|D_STREAM, "stream off no device ??");
}
}
@@ -683,9 +678,6 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev,
w = fmt->fmt.pix.width;
h = fmt->fmt.pix.height;
- /* (luvcview problem) */
- if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG)
- fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_JPEG;
#ifdef CONFIG_VIDEO_ADV_DEBUG
if (gspca_debug & D_CONF)
PDEBUG_MODE("try fmt cap", fmt->fmt.pix.pixelformat, w, h);
@@ -819,7 +811,7 @@ static int dev_close(struct inode *inode, struct file *file)
return -ERESTARTSYS;
gspca_dev->users--;
- /* if the file did capture, free the streaming resources */
+ /* if the file did the capture, free the streaming resources */
if (gspca_dev->capt_file == file) {
mutex_lock(&gspca_dev->usb_lock);
if (gspca_dev->streaming)
@@ -984,7 +976,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
switch (rb->memory) {
- case GSPCA_MEMORY_READ:
+ case GSPCA_MEMORY_READ: /* (internal call) */
case V4L2_MEMORY_MMAP:
case V4L2_MEMORY_USERPTR:
break;
@@ -994,33 +986,46 @@ static int vidioc_reqbufs(struct file *file, void *priv,
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
- /* only one file may do capture */
- if ((gspca_dev->capt_file != NULL && gspca_dev->capt_file != file)
- || gspca_dev->streaming) {
+ if (gspca_dev->memory != GSPCA_MEMORY_NO
+ && gspca_dev->memory != rb->memory) {
ret = -EBUSY;
goto out;
}
- if (rb->count == 0) { /* unrequest */
- for (i = 0; i < gspca_dev->nframes; i++) {
- if (gspca_dev->frame[i].vma_use_count) {
- ret = -EBUSY;
- goto out;
- }
- }
- frame_free(gspca_dev);
- gspca_dev->capt_file = NULL;
- } else {
- if (gspca_dev->nframes != 0) {
+ /* only one file may do the capture */
+ if (gspca_dev->capt_file != NULL
+ && gspca_dev->capt_file != file) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* if allocated, the buffers must not be mapped */
+ for (i = 0; i < gspca_dev->nframes; i++) {
+ if (gspca_dev->frame[i].vma_use_count) {
ret = -EBUSY;
goto out;
}
- gspca_dev->memory = rb->memory;
- ret = frame_alloc(gspca_dev, rb->count);
- if (ret == 0) {
- rb->count = gspca_dev->nframes;
- gspca_dev->capt_file = file;
- }
+ }
+
+ /* stop streaming */
+ if (gspca_dev->streaming) {
+ mutex_lock(&gspca_dev->usb_lock);
+ gspca_stream_off(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ }
+
+ /* free the previous allocated buffers, if any */
+ if (gspca_dev->nframes != 0) {
+ frame_free(gspca_dev);
+ gspca_dev->capt_file = NULL;
+ }
+ if (rb->count == 0) /* unrequest */
+ goto out;
+ gspca_dev->memory = rb->memory;
+ ret = frame_alloc(gspca_dev, rb->count);
+ if (ret == 0) {
+ rb->count = gspca_dev->nframes;
+ gspca_dev->capt_file = file;
}
out:
mutex_unlock(&gspca_dev->queue_lock);
@@ -1062,10 +1067,6 @@ static int vidioc_streamon(struct file *file, void *priv,
ret = -EINVAL;
goto out;
}
- if (gspca_dev->capt_file != file) {
- ret = -EINVAL;
- goto out;
- }
if (!gspca_dev->streaming) {
ret = gspca_init_transfer(gspca_dev);
if (ret < 0)
@@ -1089,7 +1090,7 @@ static int vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type buf_type)
{
struct gspca_dev *gspca_dev = priv;
- int ret;
+ int i, ret;
if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -1097,18 +1098,23 @@ static int vidioc_streamoff(struct file *file, void *priv,
return 0;
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
+
+ /* stop streaming */
if (mutex_lock_interruptible(&gspca_dev->usb_lock)) {
ret = -ERESTARTSYS;
goto out;
}
- if (gspca_dev->capt_file != file) {
- ret = -EINVAL;
- goto out2;
- }
gspca_stream_off(gspca_dev);
- ret = 0;
-out2:
mutex_unlock(&gspca_dev->usb_lock);
+
+ /* empty the application queues */
+ for (i = 0; i < gspca_dev->nframes; i++)
+ gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS;
+ gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ gspca_dev->sequence = 0;
+ atomic_set(&gspca_dev->nevent, 0);
+ ret = 0;
out:
mutex_unlock(&gspca_dev->queue_lock);
return ret;
@@ -1367,14 +1373,17 @@ static int vidioc_dqbuf(struct file *file, void *priv,
return -EINVAL;
if (v4l2_buf->memory != gspca_dev->memory)
return -EINVAL;
- if (!gspca_dev->streaming)
+
+ /* if not streaming, be sure the application will not loop forever */
+ if (!(file->f_flags & O_NONBLOCK)
+ && !gspca_dev->streaming && gspca_dev->users == 1)
return -EINVAL;
- if (gspca_dev->capt_file != file) {
- ret = -EINVAL;
- goto out;
- }
- /* only one read */
+ /* only the capturing file may dequeue */
+ if (gspca_dev->capt_file != file)
+ return -EINVAL;
+
+ /* only one dequeue / read at a time */
if (mutex_lock_interruptible(&gspca_dev->read_lock))
return -ERESTARTSYS;
@@ -1419,24 +1428,23 @@ static int vidioc_qbuf(struct file *file, void *priv,
if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+
index = v4l2_buf->index;
if ((unsigned) index >= gspca_dev->nframes) {
PDEBUG(D_FRAM,
"qbuf idx %d >= %d", index, gspca_dev->nframes);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
- frame = &gspca_dev->frame[index];
-
- if (v4l2_buf->memory != frame->v4l2_buf.memory) {
+ if (v4l2_buf->memory != gspca_dev->memory) {
PDEBUG(D_FRAM, "qbuf bad memory type");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
- if (gspca_dev->capt_file != file)
- return -EINVAL;
-
- if (mutex_lock_interruptible(&gspca_dev->queue_lock))
- return -ERESTARTSYS;
+ frame = &gspca_dev->frame[index];
if (frame->v4l2_buf.flags & BUF_ALL_FLAGS) {
PDEBUG(D_FRAM, "qbuf bad state");
ret = -EINVAL;
@@ -1495,9 +1503,6 @@ static int read_alloc(struct gspca_dev *gspca_dev,
v4l2_buf.memory = GSPCA_MEMORY_READ;
for (i = 0; i < gspca_dev->nbufread; i++) {
v4l2_buf.index = i;
-/*fixme: ugly!*/
- gspca_dev->frame[i].v4l2_buf.flags |=
- V4L2_BUF_FLAG_MAPPED;
ret = vidioc_qbuf(file, gspca_dev, &v4l2_buf);
if (ret != 0) {
PDEBUG(D_STREAM, "read qbuf err: %d", ret);
@@ -1525,17 +1530,13 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
if (!gspca_dev->present)
return POLLERR;
- /* if not streaming, the user would use read() */
- if (!gspca_dev->streaming) {
- if (gspca_dev->memory != GSPCA_MEMORY_NO) {
- ret = POLLERR; /* not the 1st time */
- goto out;
- }
+ /* if reqbufs is not done, the user would use read() */
+ if (gspca_dev->nframes == 0) {
+ if (gspca_dev->memory != GSPCA_MEMORY_NO)
+ return POLLERR; /* not the 1st time */
ret = read_alloc(gspca_dev, file);
- if (ret != 0) {
- ret = POLLERR;
- goto out;
- }
+ if (ret != 0)
+ return POLLERR;
}
if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
@@ -1545,6 +1546,7 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
goto out;
}
+ /* check the next incoming buffer */
i = gspca_dev->fr_o;
i = gspca_dev->fr_queue[i];
if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
@@ -1793,6 +1795,94 @@ void gspca_disconnect(struct usb_interface *intf)
}
EXPORT_SYMBOL(gspca_disconnect);
+/* -- 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->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\n",
+ 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/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h
index 9b645af81..78fccefcd 100644
--- a/linux/drivers/media/video/gspca/gspca.h
+++ b/linux/drivers/media/video/gspca/gspca.h
@@ -170,4 +170,6 @@ struct gspca_frame *gspca_frame_add(struct gspca_dev *gspca_dev,
struct gspca_frame *frame,
const __u8 *data,
int len);
+int gspca_auto_gain_n_exposure(struct gspca_dev *gspca_dev, int avg_lum,
+ int desired_avg_lum, int deadzone, int gain_knee, int exposure_knee);
#endif /* GSPCAV2_H */
diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c
index 4f197c1f4..5d68d3f42 100644
--- a/linux/drivers/media/video/gspca/pac207.c
+++ b/linux/drivers/media/video/gspca/pac207.c
@@ -357,70 +357,20 @@ static void sd_close(struct gspca_dev *gspca_dev)
{
}
-/* auto gain and exposure algorithm based on the knee algorithm described here:
- * <http://ytse.tricolour.net/docs/LowLightOptimization.html> */
static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i, steps, desired_avg_lum;
- int orig_gain = sd->gain;
- int orig_exposure = sd->exposure;
int avg_lum = atomic_read(&sd->avg_lum);
- if (!sd->autogain || avg_lum == -1)
+ if (avg_lum == -1)
return;
- if (sd->autogain_ignore_frames > 0) {
+ if (sd->autogain_ignore_frames > 0)
sd->autogain_ignore_frames--;
- return;
- }
-
- /* correct desired lumination for the configured brightness */
- desired_avg_lum = 100 + sd->brightness / 2;
-
- /* If we are of a multiple of deadzone, do multiple step to reach the
- desired lumination fast (with the risc of a slight overshoot) */
- steps = abs(desired_avg_lum - avg_lum) / PAC207_AUTOGAIN_DEADZONE;
-
- for (i = 0; i < steps; i++) {
- if (avg_lum > desired_avg_lum) {
- if (sd->gain > PAC207_GAIN_KNEE)
- sd->gain--;
- else if (sd->exposure > PAC207_EXPOSURE_KNEE)
- sd->exposure--;
- else if (sd->gain > PAC207_GAIN_DEFAULT)
- sd->gain--;
- else if (sd->exposure > PAC207_EXPOSURE_MIN)
- sd->exposure--;
- else if (sd->gain > PAC207_GAIN_MIN)
- sd->gain--;
- else
- break;
- } else {
- if (sd->gain < PAC207_GAIN_DEFAULT)
- sd->gain++;
- else if (sd->exposure < PAC207_EXPOSURE_KNEE)
- sd->exposure++;
- else if (sd->gain < PAC207_GAIN_KNEE)
- sd->gain++;
- else if (sd->exposure < PAC207_EXPOSURE_MAX)
- sd->exposure++;
- else if (sd->gain < PAC207_GAIN_MAX)
- sd->gain++;
- else
- break;
- }
- }
-
- if (sd->exposure != orig_exposure || sd->gain != orig_gain) {
- if (sd->exposure != orig_exposure)
- pac207_write_reg(gspca_dev, 0x0002, sd->exposure);
- if (sd->gain != orig_gain)
- pac207_write_reg(gspca_dev, 0x000e, sd->gain);
- pac207_write_reg(gspca_dev, 0x13, 0x01); /* load reg to sen */
- pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
+ else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
+ 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE,
+ PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES;
- }
}
static unsigned char *pac207_find_sof(struct gspca_dev *gspca_dev,
@@ -546,10 +496,6 @@ static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- /* don't allow mucking with exposure when using autogain */
- if (sd->autogain)
- return -EINVAL;
-
sd->exposure = val;
if (gspca_dev->streaming)
setexposure(gspca_dev);
@@ -568,10 +514,6 @@ static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- /* don't allow mucking with gain when using autogain */
- if (sd->autogain)
- return -EINVAL;
-
sd->gain = val;
if (gspca_dev->streaming)
setgain(gspca_dev);
diff --git a/linux/drivers/media/video/gspca/sonixb.c b/linux/drivers/media/video/gspca/sonixb.c
index a4594dc0e..182f4e1c3 100644
--- a/linux/drivers/media/video/gspca/sonixb.c
+++ b/linux/drivers/media/video/gspca/sonixb.c
@@ -24,8 +24,8 @@
#include "gspca.h"
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
-static const char version[] = "2.1.5";
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
MODULE_DESCRIPTION("GSPCA/SN9C102 USB Camera Driver");
@@ -35,11 +35,19 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
+ struct sd_desc sd_desc; /* our nctrls differ dependend upon the
+ sensor, so we use a per cam copy */
+ atomic_t avg_lum;
+
+ unsigned short gain;
+ unsigned short exposure;
unsigned char brightness;
- unsigned char contrast;
+ unsigned char autogain;
+ unsigned char autogain_ignore_frames;
unsigned char fr_h_sz; /* size of frame header */
char sensor; /* Type of image sensor chip */
+ char sensor_has_gain;
#define SENSOR_HV7131R 0
#define SENSOR_OV6650 1
#define SENSOR_OV7630 2
@@ -59,14 +67,26 @@ struct sd {
#define SYS_CLK 0x04
+/* We calculate the autogain at the end of the transfer of a frame, at this
+ moment a frame with the old settings is being transmitted, and a frame is
+ being captured with the old settings. So if we adjust the autogain we must
+ ignore atleast the 2 next frames for the new settings to come into effect
+ before doing any other adjustments */
+#define AUTOGAIN_IGNORE_FRAMES 3
+#define AUTOGAIN_DEADZONE 500
+#define DESIRED_AVG_LUM 7000
+
/* V4L2 controls supported by the driver */
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_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 int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
-#define SD_BRIGHTNESS 0
{
{
.id = V4L2_CID_BRIGHTNESS,
@@ -75,24 +95,57 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
- .default_value = 127,
+#define BRIGHTNESS_DEF 127
+ .default_value = BRIGHTNESS_DEF,
},
.set = sd_setbrightness,
.get = sd_getbrightness,
},
-#define SD_CONTRAST 1
{
{
- .id = V4L2_CID_CONTRAST,
+ .id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
+ .name = "Gain",
.minimum = 0,
- .maximum = 255,
+ .maximum = 511,
.step = 1,
- .default_value = 127,
+#define GAIN_DEF 255
+#define GAIN_KNEE 400
+ .default_value = GAIN_DEF,
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+#define EXPOSURE_DEF 0
+#define EXPOSURE_KNEE 353 /* 10 fps */
+ .minimum = 0,
+ .maximum = 511,
+ .step = 1,
+ .default_value = EXPOSURE_DEF,
+ .flags = 0,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Gain (and Exposure)",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
+ .flags = 0,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
},
};
@@ -161,8 +214,12 @@ static const __u8 ov6650_sensor_init[][8] =
/* Bright, contrast, etc are set througth SCBB interface.
* AVCAP on win2 do not send any data on this controls. */
/* Anyway, some registers appears to alter bright and constrat */
+
+ /* Reset sensor */
{0xa0, 0x60, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
+ /* Set clock register 0x11 low nibble is clock divider */
{0xd0, 0x60, 0x11, 0xc0, 0x1b, 0x18, 0xc1, 0x10},
+ /* Next some unknown stuff */
{0xb0, 0x60, 0x15, 0x00, 0x02, 0x18, 0xc1, 0x10},
/* {0xa0, 0x60, 0x1b, 0x01, 0x02, 0x18, 0xc1, 0x10},
* THIS SET GREEN SCREEN
@@ -171,31 +228,36 @@ static const __u8 ov6650_sensor_init[][8] =
{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
{0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
+ /* Disable autobright ? */
{0xb0, 0x60, 0x60, 0x66, 0x68, 0xd8, 0xa4, 0x10},
+ /* Some more unknown stuff */
{0xa0, 0x60, 0x68, 0x04, 0x68, 0xd8, 0xa4, 0x10},
{0xd0, 0x60, 0x17, 0x24, 0xd6, 0x04, 0x94, 0x10}, /* Clipreg */
- {0xa0, 0x60, 0x10, 0x5d, 0x99, 0x04, 0x94, 0x16},
+ {0xa0, 0x60, 0x10, 0x57, 0x99, 0x04, 0x94, 0x16},
+ /* Framerate adjust register for artificial light 50 hz flicker
+ compensation, identical to ov6630 0x2b register, see 6630 datasheet.
+ 0x4f -> (30 fps -> 25 fps), 0x00 -> no adjustment */
+ {0xa0, 0x60, 0x2b, 0x4f, 0x99, 0x04, 0x94, 0x15},
+#if 0
+ /* HDG, don't change registers 0x2d, 0x32 & 0x33 from their reset
+ defaults, doing so mucks up the framerate, where as the defaults
+ seem to work good, the combinations below have been observed
+ under windows and are kept for future reference */
{0xa0, 0x60, 0x2d, 0x0a, 0x99, 0x04, 0x94, 0x16},
{0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
{0xa0, 0x60, 0x33, 0x40, 0x99, 0x04, 0x94, 0x16},
- {0xa0, 0x60, 0x11, 0xc0, 0x99, 0x04, 0x94, 0x16},
- {0xa0, 0x60, 0x00, 0x16, 0x99, 0x04, 0x94, 0x15}, /* bright / Lumino */
- {0xa0, 0x60, 0x2b, 0xab, 0x99, 0x04, 0x94, 0x15},
- /* ?flicker o brillo */
{0xa0, 0x60, 0x2d, 0x2a, 0x99, 0x04, 0x94, 0x15},
{0xa0, 0x60, 0x2d, 0x2b, 0x99, 0x04, 0x94, 0x16},
{0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
{0xa0, 0x60, 0x33, 0x00, 0x99, 0x04, 0x94, 0x16},
- {0xa0, 0x60, 0x10, 0x57, 0x99, 0x04, 0x94, 0x16},
{0xa0, 0x60, 0x2d, 0x2b, 0x99, 0x04, 0x94, 0x16},
{0xa0, 0x60, 0x32, 0x00, 0x99, 0x04, 0x94, 0x16},
/* Low Light (Enabled: 0x32 0x1 | Disabled: 0x32 0x00) */
{0xa0, 0x60, 0x33, 0x29, 0x99, 0x04, 0x94, 0x16},
/* Low Ligth (Enabled: 0x33 0x13 | Disabled: 0x33 0x29) */
-/* {0xa0, 0x60, 0x11, 0xc1, 0x99, 0x04, 0x94, 0x16}, */
- {0xa0, 0x60, 0x00, 0x17, 0x99, 0x04, 0x94, 0x15}, /* clip? r */
- {0xa0, 0x60, 0x00, 0x18, 0x99, 0x04, 0x94, 0x15}, /* clip? r */
+#endif
};
+
static const __u8 initOv7630[] = {
0x04, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, /* r01 .. r08 */
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
@@ -207,10 +269,12 @@ static const __u8 initOv7630[] = {
static const __u8 initOv7630_3[] = {
0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, /* r09 .. r10 */
- 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
- 0x28, 0x1e, /* H & V sizes r15 .. r16 */
- 0x68, COMP1, MCK_INIT1, /* r17 .. r19 */
- 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
+ 0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
+ 0x16, 0x12, /* H & V sizes r15 .. r16 */
+ 0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
+ 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
+ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
+ 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
};
static const __u8 ov7630_sensor_init_com[][8] = {
{0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
@@ -241,14 +305,14 @@ static const __u8 ov7630_sensor_init[][8] = {
{0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
};
static const __u8 ov7630_sensor_init_3[][8] = {
- {0xa0, 0x21, 0x10, 0x36, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
- {0xa0, 0x21, 0x76, 0x03, 0xbd, 0x06, 0xf6, 0x16},
- {0xa0, 0x21, 0x11, 0x01, 0xbd, 0x06, 0xf6, 0x16},
+ {0xa0, 0x21, 0x10, 0x83, 0xbd, 0x06, 0xf6, 0x16}, /* exposure */
+ {0xa0, 0x21, 0x76, 0x00, 0xbd, 0x06, 0xf6, 0x16},
+ {0xa0, 0x21, 0x11, 0x00, 0xbd, 0x06, 0xf6, 0x16},
{0xa0, 0x21, 0x00, 0x10, 0xbd, 0x06, 0xf6, 0x15}, /* gain */
/* {0xb0, 0x21, 0x2a, 0xc0, 0x3c, 0x06, 0xf6, 0x1d},
* a0 1c,a0 1f,c0 3c frame rate ?line interval from ov6630 */
/* {0xb0, 0x21, 0x2a, 0xa0, 0x1f, 0x06, 0xf6, 0x1d}, * from win */
- {0xb0, 0x21, 0x2a, 0xa0, 0x1c, 0x06, 0xf6, 0x1d},
+ {0xb0, 0x21, 0x2a, 0x80, 0x60, 0x06, 0xf6, 0x1d},
};
static const __u8 initPas106[] = {
@@ -364,7 +428,7 @@ static void reg_w(struct usb_device *dev,
const __u8 *buffer,
int len)
{
- __u8 tmpbuf[32];
+ __u8 tmpbuf[48];
#ifdef CONFIG_VIDEO_ADV_DEBUG
if (len > sizeof tmpbuf) {
@@ -477,8 +541,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
goto err;
break;
}
- case SENSOR_TAS5130CXX:
- case SENSOR_TAS5110: {
+ case SENSOR_TAS5130CXX: {
__u8 i2c[] =
{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
@@ -489,24 +552,115 @@ static void setbrightness(struct gspca_dev *gspca_dev)
goto err;
break;
}
+ case SENSOR_TAS5110:
+ /* FIXME figure out howto control brightness on TAS5110 */
+ break;
}
return;
err:
PDEBUG(D_ERR, "i2c error brightness");
}
-static void setcontrast(struct gspca_dev *gspca_dev)
+
+static void setsensorgain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned short gain;
+
+ gain = (sd->gain + 1) >> 1;
+ if (gain > 255)
+ gain = 255;
+
+ switch (sd->sensor) {
+
+ case SENSOR_TAS5110: {
+ __u8 i2c[] =
+ {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
+
+ i2c[4] = 255 - gain;
+ if (i2c_w(gspca_dev->dev, i2c) < 0)
+ goto err;
+ break;
+ }
+ case SENSOR_OV6650: {
+ __u8 i2c[] = {0xa0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10};
+ i2c[3] = gain;
+ if (i2c_w(gspca_dev->dev, i2c) < 0)
+ goto err;
+ break;
+ }
+ }
+ return;
+err:
+ PDEBUG(D_ERR, "i2c error gain");
+}
+
+static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u8 gain;
__u8 rgb_value;
- gain = sd->contrast >> 4;
+ gain = sd->gain >> 5;
+
/* red and blue gain */
rgb_value = gain << 4 | gain;
reg_w(gspca_dev->dev, 0x10, &rgb_value, 1);
/* green gain */
rgb_value = gain;
reg_w(gspca_dev->dev, 0x11, &rgb_value, 1);
+
+ if (sd->sensor_has_gain)
+ setsensorgain(gspca_dev);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ /* translate 0 - 255 to a number of fps in a 30 - 1 scale */
+ int fps = 30 - sd->exposure * 29 / 511;
+
+ switch (sd->sensor) {
+ case SENSOR_TAS5110: {
+ __u8 reg;
+
+ /* register 19's high nibble contains the sn9c10x clock divider
+ The high nibble configures the no fps according to the
+ formula: 60 / high_nibble. With a maximum of 30 fps */
+ reg = 60 / fps;
+ if (reg > 15)
+ reg = 15;
+ reg = (reg << 4) | 0x0b;
+ reg_w(gspca_dev->dev, 0x19, &reg, 1);
+ break;
+ }
+ case SENSOR_OV6650: {
+ __u8 i2c[] = {0xa0, 0x60, 0x11, 0xc0, 0x00, 0x00, 0x00, 0x10};
+ i2c[3] = 30 / fps - 1;
+ if (i2c[3] > 15)
+ i2c[3] = 15;
+ i2c[3] |= 0xc0;
+ if (i2c_w(gspca_dev->dev, i2c) < 0)
+ PDEBUG(D_ERR, "i2c error exposure");
+ break;
+ }
+ }
+}
+
+
+static void do_autogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int avg_lum = atomic_read(&sd->avg_lum);
+
+ if (avg_lum == -1)
+ return;
+
+ if (sd->autogain_ignore_frames > 0)
+ sd->autogain_ignore_frames--;
+ else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
+ sd->brightness * DESIRED_AVG_LUM / 127,
+ AUTOGAIN_DEADZONE, GAIN_KNEE, EXPOSURE_KNEE))
+ sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES;
}
/* this function is called at probe time */
@@ -515,20 +669,27 @@ static int sd_config(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
-/* __u16 vendor; */
__u16 product;
int sif = 0;
+ /* nctrls depends upon the sensor, so we use a per cam copy */
+ memcpy(&sd->sd_desc, gspca_dev->sd_desc, sizeof(struct sd_desc));
+ gspca_dev->sd_desc = &sd->sd_desc;
+
sd->fr_h_sz = 12; /* default size of the frame header */
-/* vendor = id->idVendor; */
+ sd->sd_desc.nctrls = 2; /* default nb of ctrls */
+
product = id->idProduct;
-/* switch (vendor) { */
+/* switch (id->idVendor) { */
/* case 0x0c45: * Sonix */
switch (product) {
case 0x6001: /* SN9C102 */
case 0x6005: /* SN9C101 */
case 0x6007: /* SN9C101 */
sd->sensor = SENSOR_TAS5110;
+ sd->sensor_has_gain = 1;
+ sd->sd_desc.nctrls = 4;
+ sd->sd_desc.dq_callback = do_autogain;
sif = 1;
break;
case 0x6009: /* SN9C101 */
@@ -539,6 +700,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
break;
case 0x6011: /* SN9C101 - SN9C101G */
sd->sensor = SENSOR_OV6650;
+ sd->sensor_has_gain = 1;
+ sd->sd_desc.nctrls = 4;
+ sd->sd_desc.dq_callback = do_autogain;
sif = 1;
break;
case 0x6019: /* SN9C101 */
@@ -573,13 +737,15 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->epaddr = 0x01;
if (!sif) {
cam->cam_mode = vga_mode;
- cam->nmodes = sizeof vga_mode / sizeof vga_mode[0];
+ cam->nmodes = ARRAY_SIZE(vga_mode);
} else {
cam->cam_mode = sif_mode;
- cam->nmodes = sizeof sif_mode / sizeof sif_mode[0];
+ cam->nmodes = ARRAY_SIZE(sif_mode);
}
- sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
- sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->gain = GAIN_DEF;
+ sd->exposure = EXPOSURE_DEF;
+ sd->autogain = AUTOGAIN_DEF;
if (sd->sensor == SENSOR_OV7630_3) /* jfm: from win trace */
reg_w(gspca_dev->dev, 0x01, probe_ov7630, sizeof probe_ov7630);
return 0;
@@ -622,6 +788,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
const __u8 *sn9c10x;
__u8 reg01, reg17;
__u8 reg17_19[3];
+ static const __u8 reg15[2] = { 0x28, 0x1e };
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
switch (sd->sensor) {
@@ -684,7 +851,7 @@ static void sd_start(struct gspca_dev *gspca_dev)
case SENSOR_OV7630_3:
reg01 = 0x44;
reg17 = 0x68;
- l = 0x10;
+ l = sizeof initOv7630_3;
break;
default:
reg01 = sn9c10x[0];
@@ -742,18 +909,21 @@ static void sd_start(struct gspca_dev *gspca_dev)
break;
}
/* H_size V_size 0x28, 0x1e maybe 640x480 */
- reg_w(dev, 0x15, &sn9c10x[0x15 - 1], 2);
+ reg_w(dev, 0x15, reg15, 2);
/* compression register */
reg_w(dev, 0x18, &reg17_19[1], 1);
- /* H_start */ /*fixme: not ov7630*/
- reg_w(dev, 0x12, &sn9c10x[0x12 - 1], 1);
- /* V_START */ /*fixme: not ov7630*/
- reg_w(dev, 0x13, &sn9c10x[0x13 - 1], 1);
+ if (sd->sensor != SENSOR_OV7630_3) {
+ /* H_start */
+ reg_w(dev, 0x12, &sn9c10x[0x12 - 1], 1);
+ /* V_START */
+ reg_w(dev, 0x13, &sn9c10x[0x13 - 1], 1);
+ }
/* reset 0x17 SensorClk enable inv Clk 0x60 */
/*fixme: ov7630 [17]=68 8f (+20 if 102)*/
reg_w(dev, 0x17, &reg17_19[0], 1);
/*MCKSIZE ->3 */ /*fixme: not ov7630*/
- reg_w(dev, 0x19, &reg17_19[2], 1);
+ if (sd->sensor != SENSOR_OV7630_3)
+ reg_w(dev, 0x19, &reg17_19[2], 1);
/* AE_STRX AE_STRY AE_ENDX AE_ENDY */
reg_w(dev, 0x1c, &sn9c10x[0x1c - 1], 4);
/* Enable video transfert */
@@ -762,13 +932,17 @@ static void sd_start(struct gspca_dev *gspca_dev)
reg_w(dev, 0x18, &reg17_19[1], 2);
msleep(20);
- setcontrast(gspca_dev);
+ setgain(gspca_dev);
setbrightness(gspca_dev);
+ setexposure(gspca_dev);
+
+ sd->autogain_ignore_frames = 0;
+ atomic_set(&sd->avg_lum, -1);
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
- __u8 ByteSend = 0;
+ __u8 ByteSend;
ByteSend = 0x09; /* 0X00 */
reg_w(gspca_dev->dev, 0x01, &ByteSend, 1);
@@ -787,8 +961,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
unsigned char *data, /* isoc packet */
int len) /* iso packet length */
{
- struct sd *sd;
int i;
+ struct sd *sd = (struct sd *) gspca_dev;
if (len > 6 && len < 24) {
for (i = 0; i < len - 6; i++) {
@@ -800,7 +974,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
&& data[5 + i] == 0x96) { /* start of frame */
frame = gspca_frame_add(gspca_dev, LAST_PACKET,
frame, data, 0);
- sd = (struct sd *) gspca_dev;
+ if (i < (len - 10)) {
+ atomic_set(&sd->avg_lum, data[i + 8] +
+ (data[i + 9] << 8));
+ } else {
+ atomic_set(&sd->avg_lum, -1);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ PDEBUG(D_STREAM, "packet too short to "
+ "get avg brightness");
+#endif
+ }
data += i + sd->fr_h_sz;
len -= i + sd->fr_h_sz;
gspca_frame_add(gspca_dev, FIRST_PACKET,
@@ -831,26 +1014,74 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+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;
- sd->contrast = val;
+ *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)
- setcontrast(gspca_dev);
+ setexposure(gspca_dev);
+ return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ /* 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 = AUTOGAIN_IGNORE_FRAMES;
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+ }
+ }
+
return 0;
}
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->contrast;
+ *val = sd->autogain;
return 0;
}
/* sub-driver description */
-static struct sd_desc sd_desc = {
+static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c
index 1129cbeb8..ba89d924b 100644
--- a/linux/drivers/media/video/gspca/vc032x.c
+++ b/linux/drivers/media/video/gspca/vc032x.c
@@ -24,8 +24,8 @@
#include "gspca.h"
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 5)
-static const char version[] = "2.1.5";
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 1, 7)
+static const char version[] = "2.1.7";
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
MODULE_DESCRIPTION("GSPCA/VC032X USB Camera Driver");
@@ -58,7 +58,6 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
static struct ctrl sd_ctrls[] = {
-#define SD_AUTOGAIN 0
{
{
.id = V4L2_CID_AUTOGAIN,
@@ -67,20 +66,22 @@ static struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
- .default_value = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
},
.set = sd_setautogain,
.get = sd_getautogain,
},
-#define SD_FREQ 1
{
{
.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 */
+ .maximum = 2, /* 0: No, 1: 50Hz, 2:60Hz */
.step = 1,
+#define FREQ_DEF 1
+ .default_value = FREQ_DEF,
.default_value = 1,
},
.set = sd_setfreq,
@@ -89,12 +90,12 @@ static struct ctrl sd_ctrls[] = {
};
static struct v4l2_pix_format vc0321_mode[] = {
- {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ {320, 240, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
.bytesperline = 320 * 2,
.sizeimage = 320 * 240 * 2,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 1},
- {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ {640, 480, V4L2_PIX_FMT_YUV420, V4L2_FIELD_NONE,
.bytesperline = 640 * 2,
.sizeimage = 640 * 480 * 2,
.colorspace = V4L2_COLORSPACE_SRGB,
@@ -1598,28 +1599,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct cam *cam;
__u8 tmp2[4];
int sensor;
- __u16 vendor;
__u16 product;
- vendor = id->idVendor;
product = id->idProduct;
- switch (vendor) {
- case 0x046d: /* Logitech Labtec */
-/* switch (product) { */
-/* case 0x0892: */
-/* case 0x0896: */
- sd->bridge = BRIDGE_VC0321;
-/* break; */
-/* } */
- break;
+ sd->bridge = BRIDGE_VC0321;
+ switch (id->idVendor) {
case 0x0ac8: /* Vimicro z-star */
switch (product) {
- case 0x0321:
- case 0x0328:
- case 0xc001:
- case 0xc002:
- sd->bridge = BRIDGE_VC0321;
- break;
case 0x0323:
sd->bridge = BRIDGE_VC0323;
break;
@@ -1639,10 +1625,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->epaddr = 0x02;
if (sd->bridge == BRIDGE_VC0321) {
cam->cam_mode = vc0321_mode;
- cam->nmodes = sizeof vc0321_mode / sizeof vc0321_mode[0];
+ cam->nmodes = ARRAY_SIZE(vc0321_mode);
} else {
cam->cam_mode = vc0323_mode;
- cam->nmodes = sizeof vc0323_mode / sizeof vc0323_mode[0];
+ cam->nmodes = ARRAY_SIZE(vc0323_mode);
}
vc0321_reset(gspca_dev);
@@ -1678,7 +1664,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
sd->qindex = 7;
- sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
+ sd->autogain = AUTOGAIN_DEF;
+ sd->lightfreq = FREQ_DEF;
if (sd->bridge == BRIDGE_VC0321) {
reg_r(dev, 0x8a, 0, tmp2, 3);