diff options
Diffstat (limited to 'linux/drivers/media/video/gspca')
51 files changed, 5491 insertions, 2197 deletions
diff --git a/linux/drivers/media/video/gspca/Kconfig b/linux/drivers/media/video/gspca/Kconfig index 770fb699d..ee6a691df 100644 --- a/linux/drivers/media/video/gspca/Kconfig +++ b/linux/drivers/media/video/gspca/Kconfig @@ -18,6 +18,7 @@ menuconfig USB_GSPCA if USB_GSPCA && VIDEO_V4L2 source "drivers/media/video/gspca/m5602/Kconfig" +source "drivers/media/video/gspca/stv06xx/Kconfig" config USB_GSPCA_CONEX tristate "Conexant Camera Driver" diff --git a/linux/drivers/media/video/gspca/Makefile b/linux/drivers/media/video/gspca/Makefile index 6c8046e23..bd8d9ee40 100644 --- a/linux/drivers/media/video/gspca/Makefile +++ b/linux/drivers/media/video/gspca/Makefile @@ -47,4 +47,4 @@ gspca_vc032x-objs := vc032x.o gspca_zc3xx-objs := zc3xx.o obj-$(CONFIG_USB_M5602) += m5602/ - +obj-$(CONFIG_USB_STV06XX) += stv06xx/ diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c index de28354ea..1753f5bb3 100644 --- a/linux/drivers/media/video/gspca/conex.c +++ b/linux/drivers/media/video/gspca/conex.c @@ -93,7 +93,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 176, .sizeimage = 176 * 144 * 3 / 8 + 590, diff --git a/linux/drivers/media/video/gspca/etoms.c b/linux/drivers/media/video/gspca/etoms.c index 28869ef26..84b56c303 100644 --- a/linux/drivers/media/video/gspca/etoms.c +++ b/linux/drivers/media/video/gspca/etoms.c @@ -112,7 +112,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240, @@ -125,7 +125,7 @@ static struct v4l2_pix_format vga_mode[] = { .priv = 0}, */ }; -static struct v4l2_pix_format sif_mode[] = { +static const struct v4l2_pix_format sif_mode[] = { {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 176, .sizeimage = 176 * 144, diff --git a/linux/drivers/media/video/gspca/finepix.c b/linux/drivers/media/video/gspca/finepix.c index 03cb94466..afc8b2dd3 100644 --- a/linux/drivers/media/video/gspca/finepix.c +++ b/linux/drivers/media/video/gspca/finepix.c @@ -72,7 +72,7 @@ struct usb_fpix { } /* These cameras only support 320x200. */ -static struct v4l2_pix_format fpix_mode[1] = { +static const struct v4l2_pix_format fpix_mode[1] = { { 320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c index d725663fc..479b4feea 100644 --- a/linux/drivers/media/video/gspca/gspca.c +++ b/linux/drivers/media/video/gspca/gspca.c @@ -649,8 +649,11 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) "usb_submit_urb [%d] err %d", n, ret); gspca_dev->streaming = 0; destroy_urbs(gspca_dev); - if (ret == -ENOSPC) + if (ret == -ENOSPC) { + msleep(20); /* wait for kill + * complete */ break; /* try the previous alt */ + } goto out; } } @@ -668,7 +671,7 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev) ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0); if (ret < 0) - PDEBUG(D_ERR|D_STREAM, "set interface 0 err %d", ret); + PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret); return ret; } @@ -782,8 +785,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct gspca_dev *gspca_dev = priv; int mode; - if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; mode = gspca_dev->curr_mode; memcpy(&fmt->fmt.pix, &gspca_dev->cam.cam_mode[mode], sizeof fmt->fmt.pix); @@ -795,8 +796,6 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, { int w, h, mode, mode2; - if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; w = fmt->fmt.pix.width; h = fmt->fmt.pix.height; @@ -886,7 +885,7 @@ static void gspca_release(struct video_device *vfd) kfree(gspca_dev); } -static int dev_open(struct inode *inode, struct file *file) +static int dev_open(struct file *file) { struct gspca_dev *gspca_dev; int ret; @@ -933,7 +932,7 @@ out: return ret; } -static int dev_close(struct inode *inode, struct file *file) +static int dev_close(struct file *file) { struct gspca_dev *gspca_dev = file->private_data; @@ -1078,6 +1077,35 @@ static int vidioc_g_ctrl(struct file *file, void *priv, return -EINVAL; } +/*fixme: have an audio flag in gspca_dev?*/ +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + if (audio->index != 0) + return -EINVAL; + return 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + memset(audio, 0, sizeof *audio); + strcpy(audio->name, "Microphone"); + return 0; +} + +static int vidioc_enumaudio(struct file *file, void *priv, + struct v4l2_audio *audio) +{ + if (audio->index != 0) + return -EINVAL; + + strcpy(audio->name, "Microphone"); + audio->capability = 0; + audio->mode = 0; + return 0; +} + static int vidioc_querymenu(struct file *file, void *priv, struct v4l2_querymenu *qmenu) { @@ -1121,8 +1149,6 @@ static int vidioc_reqbufs(struct file *file, void *priv, struct gspca_dev *gspca_dev = priv; int i, ret = 0; - if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; switch (rb->memory) { case GSPCA_MEMORY_READ: /* (internal call) */ case V4L2_MEMORY_MMAP: @@ -1187,8 +1213,7 @@ static int vidioc_querybuf(struct file *file, void *priv, struct gspca_dev *gspca_dev = priv; struct gspca_frame *frame; - if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE - || v4l2_buf->index < 0 + if (v4l2_buf->index < 0 || v4l2_buf->index >= gspca_dev->nframes) return -EINVAL; @@ -1211,7 +1236,8 @@ static int vidioc_streamon(struct file *file, void *priv, ret = -ENODEV; goto out; } - if (gspca_dev->nframes == 0) { + if (gspca_dev->nframes == 0 + || !(gspca_dev->frame[0].v4l2_buf.flags & V4L2_BUF_FLAG_QUEUED)) { ret = -EINVAL; goto out; } @@ -1288,10 +1314,10 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv, struct gspca_dev *gspca_dev = priv; int ret; - if (mutex_lock_interruptible(&gspca_dev->usb_lock)) - return -ERESTARTSYS; if (!gspca_dev->sd_desc->set_jcomp) return -EINVAL; + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; ret = gspca_dev->sd_desc->set_jcomp(gspca_dev, jpegcomp); mutex_unlock(&gspca_dev->usb_lock); return ret; @@ -1305,6 +1331,17 @@ static int vidioc_g_parm(struct file *filp, void *priv, memset(parm, 0, sizeof *parm); parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; 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; + ret = gspca_dev->sd_desc->get_streamparm(gspca_dev, parm); + mutex_unlock(&gspca_dev->usb_lock); + return ret; + } + return 0; } @@ -1319,6 +1356,17 @@ static int vidioc_s_parm(struct file *filp, void *priv, parm->parm.capture.readbuffers = gspca_dev->nbufread; else gspca_dev->nbufread = n; + + if (gspca_dev->sd_desc->set_streamparm) { + int ret; + + if (mutex_lock_interruptible(&gspca_dev->usb_lock)) + return -ERESTARTSYS; + ret = gspca_dev->sd_desc->set_streamparm(gspca_dev, parm); + mutex_unlock(&gspca_dev->usb_lock); + return ret; + } + return 0; } @@ -1507,8 +1555,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, int i, ret; PDEBUG(D_FRAM, "dqbuf"); - if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; if (v4l2_buf->memory != gspca_dev->memory) return -EINVAL; @@ -1563,8 +1609,6 @@ static int vidioc_qbuf(struct file *file, void *priv, int i, index, ret; PDEBUG(D_FRAM, "qbuf %d", v4l2_buf->index); - if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; if (mutex_lock_interruptible(&gspca_dev->queue_lock)) return -ERESTARTSYS; @@ -1768,17 +1812,13 @@ out: return ret; } -static struct file_operations dev_fops = { +static struct v4l2_file_operations dev_fops = { .owner = THIS_MODULE, .open = dev_open, .release = dev_close, .read = dev_read, .mmap = dev_mmap, - .ioctl = video_ioctl2, -#ifdef CONFIG_COMPAT - .compat_ioctl = v4l_compat_ioctl32, -#endif - .llseek = no_llseek, + .unlocked_ioctl = video_ioctl2, .poll = dev_poll, }; @@ -1794,6 +1834,9 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = { .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_enumaudio = vidioc_enumaudio, .vidioc_querymenu = vidioc_querymenu, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h index 15db13296..c90af9cb1 100644 --- a/linux/drivers/media/video/gspca/gspca.h +++ b/linux/drivers/media/video/gspca/gspca.h @@ -56,7 +56,7 @@ extern int gspca_debug; /* device information - set at probe time */ struct cam { int bulk_size; /* buffer size when image transfer by bulk */ - struct v4l2_pix_format *cam_mode; /* size nmodes */ + const struct v4l2_pix_format *cam_mode; /* size nmodes */ char nmodes; __u8 bulk_nurbs; /* number of URBs in bulk mode * - cannot be > MAX_NURBS @@ -74,6 +74,8 @@ typedef void (*cam_v_op) (struct gspca_dev *); typedef int (*cam_cf_op) (struct gspca_dev *, const struct usb_device_id *); typedef int (*cam_jpg_op) (struct gspca_dev *, struct v4l2_jpegcompression *); +typedef int (*cam_streamparm_op) (struct gspca_dev *, + struct v4l2_streamparm *); typedef int (*cam_qmnu_op) (struct gspca_dev *, struct v4l2_querymenu *); typedef void (*cam_pkt_op) (struct gspca_dev *gspca_dev, @@ -106,6 +108,8 @@ struct sd_desc { cam_jpg_op get_jcomp; cam_jpg_op set_jcomp; cam_qmnu_op querymenu; + cam_streamparm_op get_streamparm; + cam_streamparm_op set_streamparm; }; /* packet types when moving from iso buf to frame buf */ diff --git a/linux/drivers/media/video/gspca/m5602/m5602_bridge.h b/linux/drivers/media/video/gspca/m5602/m5602_bridge.h index c1c7ce524..a3f3b7a0c 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_bridge.h +++ b/linux/drivers/media/video/gspca/m5602/m5602_bridge.h @@ -109,7 +109,6 @@ static const unsigned char sensor_urb_skeleton[] = { 0x13, M5602_XB_I2C_CTRL, 0x81, 0x11 }; -/* m5602 device descriptor, currently it just wraps the m5602_camera struct */ struct sd { struct gspca_dev gspca_dev; @@ -134,4 +133,10 @@ int m5602_read_bridge( int m5602_write_bridge( struct sd *sd, u8 address, u8 i2c_data); +int m5602_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + +int m5602_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + #endif diff --git a/linux/drivers/media/video/gspca/m5602/m5602_core.c b/linux/drivers/media/video/gspca/m5602/m5602_core.c index fd6ce384b..ed906fe31 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_core.c +++ b/linux/drivers/media/video/gspca/m5602/m5602_core.c @@ -24,7 +24,7 @@ /* Kernel module parameters */ int force_sensor; -int dump_bridge; +static int dump_bridge; int dump_sensor; static const __devinitdata struct usb_device_id m5602_table[] = { @@ -80,6 +80,97 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data) return (err < 0) ? err : 0; } +int m5602_read_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + + if (!len || len > sd->sensor->i2c_regW) + return -EINVAL; + + do { + err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); + } while ((*i2c_data & I2C_BUSY) && !err); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, + sd->sensor->i2c_slave_id); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); + if (err < 0) + goto out; + + if (sd->sensor->i2c_regW == 1) { + err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, len); + if (err < 0) + goto out; + + err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08); + if (err < 0) + goto out; + } else { + err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len); + if (err < 0) + goto out; + } + + for (i = 0; (i < len) && !err; i++) { + err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); + + PDEBUG(D_CONF, "Reading sensor register " + "0x%x containing 0x%x ", address, *i2c_data); + } +out: + return err; +} + +int m5602_write_sensor(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len) +{ + int err, i; + u8 *p; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + /* No sensor with a data width larger than 16 bits has yet been seen */ + if (len > sd->sensor->i2c_regW || !len) + return -EINVAL; + + memcpy(buf, sensor_urb_skeleton, + sizeof(sensor_urb_skeleton)); + + buf[11] = sd->sensor->i2c_slave_id; + buf[15] = address; + + /* Special case larger sensor writes */ + p = buf + 16; + + /* Copy a four byte write sequence for each byte to be written to */ + for (i = 0; i < len; i++) { + memcpy(p, sensor_urb_skeleton + 16, 4); + p[3] = i2c_data[i]; + p += 4; + PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x", + address, i2c_data[i]); + } + + /* Copy the tailer */ + memcpy(p, sensor_urb_skeleton + 20, 4); + + /* Set the total length */ + p[3] = 0x10 + len; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x19, + 0x0000, buf, + 20 + len * 4, M5602_URB_MSG_TIMEOUT); + + return (err < 0) ? err : 0; +} + /* Dump all the registers of the m5602 bridge, unfortunately this breaks the camera until it's power cycled */ static void m5602_dump_bridge(struct sd *sd) @@ -150,11 +241,15 @@ static int m5602_start_transfer(struct gspca_dev *gspca_dev) /* Send start command to the camera */ const u8 buffer[4] = {0x13, 0xf9, 0x0f, 0x01}; + + if (sd->sensor->start) + sd->sensor->start(sd); + memcpy(buf, buffer, sizeof(buffer)); err = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0), 0x04, 0x40, 0x19, 0x0000, buf, - 4, M5602_URB_MSG_TIMEOUT); + sizeof(buffer), M5602_URB_MSG_TIMEOUT); PDEBUG(D_STREAM, "Transfer started"); return (err < 0) ? err : 0; @@ -284,6 +379,7 @@ static int __init mod_m5602_init(void) PDEBUG(D_PROBE, "registered"); return 0; } + static void __exit mod_m5602_exit(void) { usb_deregister(&sd_driver); diff --git a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c index fb700c2d0..c0e71c331 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c +++ b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c @@ -18,6 +18,8 @@ #include "m5602_mt9m111.h" +static void mt9m111_dump_registers(struct sd *sd); + int mt9m111_probe(struct sd *sd) { u8 data[2] = {0x00, 0x00}; @@ -44,12 +46,12 @@ int mt9m111_probe(struct sd *sd) } else { data[0] = preinit_mt9m111[i][2]; data[1] = preinit_mt9m111[i][3]; - mt9m111_write_sensor(sd, + m5602_write_sensor(sd, preinit_mt9m111[i][1], data, 2); } } - if (mt9m111_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) + if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) return -ENODEV; if ((data[0] == 0x14) && (data[1] == 0x3a)) { @@ -72,7 +74,7 @@ int mt9m111_init(struct sd *sd) int i, err = 0; /* Init the sensor */ - for (i = 0; i < ARRAY_SIZE(init_mt9m111); i++) { + for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) { u8 data[2]; if (init_mt9m111[i][0] == BRIDGE) { @@ -82,7 +84,7 @@ int mt9m111_init(struct sd *sd) } else { data[0] = init_mt9m111[i][2]; data[1] = init_mt9m111[i][3]; - err = mt9m111_write_sensor(sd, + err = m5602_write_sensor(sd, init_mt9m111[i][1], data, 2); } } @@ -104,12 +106,12 @@ int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) u8 data[2] = {0x00, 0x00}; struct sd *sd = (struct sd *) gspca_dev; - err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, + err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); *val = data[0] & MT9M111_RMB_MIRROR_ROWS; PDEBUG(D_V4L2, "Read vertical flip %d", *val); - return (err < 0) ? err : 0; + return err; } int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val) @@ -121,19 +123,19 @@ int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val) PDEBUG(D_V4L2, "Set vertical flip to %d", val); /* Set the correct page map */ - err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); + err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); if (err < 0) goto out; - err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); + err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); if (err < 0) goto out; data[0] = (data[0] & 0xfe) | val; - err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, + err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); out: - return (err < 0) ? err : 0; + return err; } int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -142,12 +144,12 @@ int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) u8 data[2] = {0x00, 0x00}; struct sd *sd = (struct sd *) gspca_dev; - err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, + err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); *val = data[0] & MT9M111_RMB_MIRROR_COLS; PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - return (err < 0) ? err : 0; + return err; } int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val) @@ -159,19 +161,19 @@ int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val) PDEBUG(D_V4L2, "Set horizontal flip to %d", val); /* Set the correct page map */ - err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); + err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); if (err < 0) goto out; - err = mt9m111_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); + err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); if (err < 0) goto out; data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02); - err = mt9m111_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, + err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); out: - return (err < 0) ? err : 0; + return err; } int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val) @@ -180,7 +182,7 @@ int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val) u8 data[2] = {0x00, 0x00}; struct sd *sd = (struct sd *) gspca_dev; - err = mt9m111_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2); + err = m5602_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2); tmp = ((data[1] << 8) | data[0]); *val = ((tmp & (1 << 10)) * 2) | @@ -190,7 +192,7 @@ int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val) PDEBUG(D_V4L2, "Read gain %d", *val); - return (err < 0) ? err : 0; + return err; } int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) @@ -200,7 +202,7 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; /* Set the correct page map */ - err = mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); + err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); if (err < 0) goto out; @@ -225,90 +227,13 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp, data[1], data[0]); - err = mt9m111_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN, + err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2); out: - return (err < 0) ? err : 0; -} - -int mt9m111_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) { - int err, i; - - do { - err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); - } while ((*i2c_data & I2C_BUSY) && !err); - if (err < 0) - goto out; - - err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, - sd->sensor->i2c_slave_id); - if (err < 0) - goto out; - - err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); - if (err < 0) - goto out; - - err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x1a); - if (err < 0) - goto out; - - for (i = 0; i < len && !err; i++) { - err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); - - PDEBUG(D_CONF, "Reading sensor register " - "0x%x contains 0x%x ", address, *i2c_data); - } -out: - return (err < 0) ? err : 0; -} - -int mt9m111_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) -{ - int err, i; - u8 *p; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - /* No sensor with a data width larger - than 16 bits has yet been seen, nor with 0 :p*/ - if (len > 2 || !len) - return -EINVAL; - - memcpy(buf, sensor_urb_skeleton, - sizeof(sensor_urb_skeleton)); - - buf[11] = sd->sensor->i2c_slave_id; - buf[15] = address; - - p = buf + 16; - - /* Copy a four byte write sequence for each byte to be written to */ - for (i = 0; i < len; i++) { - memcpy(p, sensor_urb_skeleton + 16, 4); - p[3] = i2c_data[i]; - p += 4; - PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x", - address, i2c_data[i]); - } - - /* Copy the tailer */ - memcpy(p, sensor_urb_skeleton + 20, 4); - - /* Set the total length */ - p[3] = 0x10 + len; - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, 0x19, - 0x0000, buf, - 20 + len * 4, M5602_URB_MSG_TIMEOUT); - - return (err < 0) ? err : 0; + return err; } -void mt9m111_dump_registers(struct sd *sd) +static void mt9m111_dump_registers(struct sd *sd) { u8 address, value[2] = {0x00, 0x00}; @@ -316,27 +241,27 @@ void mt9m111_dump_registers(struct sd *sd) info("Dumping the mt9m111 sensor core registers"); value[1] = MT9M111_SENSOR_CORE; - mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); + m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); for (address = 0; address < 0xff; address++) { - mt9m111_read_sensor(sd, address, value, 2); + m5602_read_sensor(sd, address, value, 2); info("register 0x%x contains 0x%x%x", address, value[0], value[1]); } info("Dumping the mt9m111 color pipeline registers"); value[1] = MT9M111_COLORPIPE; - mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); + m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); for (address = 0; address < 0xff; address++) { - mt9m111_read_sensor(sd, address, value, 2); + m5602_read_sensor(sd, address, value, 2); info("register 0x%x contains 0x%x%x", address, value[0], value[1]); } info("Dumping the mt9m111 camera control registers"); value[1] = MT9M111_CAMERA_CONTROL; - mt9m111_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); + m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); for (address = 0; address < 0xff; address++) { - mt9m111_read_sensor(sd, address, value, 2); + m5602_read_sensor(sd, address, value, 2); info("register 0x%x contains 0x%x%x", address, value[0], value[1]); } diff --git a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h index 315209d5a..e795ab7a3 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h +++ b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h @@ -87,14 +87,6 @@ int mt9m111_probe(struct sd *sd); int mt9m111_init(struct sd *sd); int mt9m111_power_down(struct sd *sd); -int mt9m111_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - -int mt9m111_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - -void mt9m111_dump_registers(struct sd *sd); - int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); @@ -106,14 +98,12 @@ static struct m5602_sensor mt9m111 = { .name = "MT9M111", .i2c_slave_id = 0xba, + .i2c_regW = 2, .probe = mt9m111_probe, .init = mt9m111_init, .power_down = mt9m111_power_down, - .read_sensor = mt9m111_read_sensor, - .write_sensor = mt9m111_write_sensor, - .nctrls = 3, .ctrls = { { @@ -1003,7 +993,7 @@ static const unsigned char init_mt9m111[][4] = {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, /* 639*/ {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c index 07ef2b3db..dde5075ed 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c +++ b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c @@ -47,86 +47,30 @@ static } }, { + .ident = "ASUS A6Ja", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), + DMI_MATCH(DMI_PRODUCT_NAME, "A6J") + } + }, + { .ident = "ASUS A6Kt", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."), DMI_MATCH(DMI_PRODUCT_NAME, "A6Kt") } }, + { + .ident = "Alienware Aurora m9700", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "alienware"), + DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700") + } + }, { } }; -int ov9650_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) -{ - int err, i; - - /* The ov9650 registers have a max depth of one byte */ - if (len > 1 || !len) - return -EINVAL; - - do { - err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); - } while ((*i2c_data & I2C_BUSY) && !err); - - m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, - ov9650.i2c_slave_id); - m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); - m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len); - m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08); - - for (i = 0; i < len; i++) { - err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); - - PDEBUG(D_CONF, "Reading sensor register " - "0x%x containing 0x%x ", address, *i2c_data); - } - return (err < 0) ? err : 0; -} - -int ov9650_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) -{ - int err, i; - u8 *p; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - /* The ov9650 only supports one byte writes */ - if (len > 1 || !len) - return -EINVAL; - - memcpy(buf, sensor_urb_skeleton, - sizeof(sensor_urb_skeleton)); - - buf[11] = sd->sensor->i2c_slave_id; - buf[15] = address; - - /* Special case larger sensor writes */ - p = buf + 16; - - /* Copy a four byte write sequence for each byte to be written to */ - for (i = 0; i < len; i++) { - memcpy(p, sensor_urb_skeleton + 16, 4); - p[3] = i2c_data[i]; - p += 4; - PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x", - address, i2c_data[i]); - } - - /* Copy the tailer */ - memcpy(p, sensor_urb_skeleton + 20, 4); - - /* Set the total length */ - p[3] = 0x10 + len; - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, 0x19, - 0x0000, buf, - 20 + len * 4, M5602_URB_MSG_TIMEOUT); - - return (err < 0) ? err : 0; -} +static void ov9650_dump_registers(struct sd *sd); int ov9650_probe(struct sd *sd) { @@ -148,16 +92,16 @@ int ov9650_probe(struct sd *sd) for (i = 0; i < ARRAY_SIZE(preinit_ov9650); i++) { u8 data = preinit_ov9650[i][2]; if (preinit_ov9650[i][0] == SENSOR) - ov9650_write_sensor(sd, + m5602_write_sensor(sd, preinit_ov9650[i][1], &data, 1); else m5602_write_bridge(sd, preinit_ov9650[i][1], data); } - if (ov9650_read_sensor(sd, OV9650_PID, &prod_id, 1)) + if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1)) return -ENODEV; - if (ov9650_read_sensor(sd, OV9650_VER, &ver_id, 1)) + if (m5602_read_sensor(sd, OV9650_VER, &ver_id, 1)) return -ENODEV; if ((prod_id == 0x96) && (ver_id == 0x52)) { @@ -186,34 +130,90 @@ int ov9650_init(struct sd *sd) for (i = 0; i < ARRAY_SIZE(init_ov9650) && !err; i++) { data = init_ov9650[i][2]; if (init_ov9650[i][0] == SENSOR) - err = ov9650_write_sensor(sd, init_ov9650[i][1], + err = m5602_write_sensor(sd, init_ov9650[i][1], &data, 1); else err = m5602_write_bridge(sd, init_ov9650[i][1], data); } - if (!err && dmi_check_system(ov9650_flip_dmi_table)) { + if (dmi_check_system(ov9650_flip_dmi_table) && !err) { info("vflip quirk active"); data = 0x30; - err = ov9650_write_sensor(sd, OV9650_MVFP, &data, 1); + err = m5602_write_sensor(sd, OV9650_MVFP, &data, 1); } + return err; +} - return (err < 0) ? err : 0; +int ov9650_start(struct sd *sd) +{ + int i, err = 0; + struct cam *cam = &sd->gspca_dev.cam; + + for (i = 0; i < ARRAY_SIZE(res_init_ov9650) && !err; i++) { + u8 data = res_init_ov9650[i][1]; + err = m5602_write_bridge(sd, res_init_ov9650[i][0], data); + } + if (err < 0) + return err; + + switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) + { + case 640: + PDEBUG(D_V4L2, "Configuring camera for VGA mode"); + + for (i = 0; i < ARRAY_SIZE(VGA_ov9650) && !err; i++) { + u8 data = VGA_ov9650[i][2]; + if (VGA_ov9650[i][0] == SENSOR) + err = m5602_write_sensor(sd, + VGA_ov9650[i][1], &data, 1); + else + err = m5602_write_bridge(sd, VGA_ov9650[i][1], data); + } + break; + + case 352: + PDEBUG(D_V4L2, "Configuring camera for CIF mode"); + + for (i = 0; i < ARRAY_SIZE(CIF_ov9650) && !err; i++) { + u8 data = CIF_ov9650[i][2]; + if (CIF_ov9650[i][0] == SENSOR) + err = m5602_write_sensor(sd, + CIF_ov9650[i][1], &data, 1); + else + err = m5602_write_bridge(sd, CIF_ov9650[i][1], data); + } + break; + + case 320: + PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); + + for (i = 0; i < ARRAY_SIZE(QVGA_ov9650) && !err; i++) { + u8 data = QVGA_ov9650[i][2]; + if (QVGA_ov9650[i][0] == SENSOR) + err = m5602_write_sensor(sd, + QVGA_ov9650[i][1], &data, 1); + else + err = m5602_write_bridge(sd, QVGA_ov9650[i][1], data); + } + break; + } + return err; } int ov9650_power_down(struct sd *sd) { - int i; - for (i = 0; i < ARRAY_SIZE(power_down_ov9650); i++) { + int i, err = 0; + for (i = 0; i < ARRAY_SIZE(power_down_ov9650) && !err; i++) { u8 data = power_down_ov9650[i][2]; if (power_down_ov9650[i][0] == SENSOR) - ov9650_write_sensor(sd, + err = m5602_write_sensor(sd, power_down_ov9650[i][1], &data, 1); else - m5602_write_bridge(sd, power_down_ov9650[i][1], data); + err = m5602_write_bridge(sd, power_down_ov9650[i][1], + data); } - return 0; + return err; } int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) @@ -222,24 +222,24 @@ int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; int err; - err = ov9650_read_sensor(sd, OV9650_COM1, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_COM1, &i2c_data, 1); if (err < 0) goto out; *val = i2c_data & 0x03; - err = ov9650_read_sensor(sd, OV9650_AECH, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_AECH, &i2c_data, 1); if (err < 0) goto out; *val |= (i2c_data << 2); - err = ov9650_read_sensor(sd, OV9650_AECHM, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_AECHM, &i2c_data, 1); if (err < 0) goto out; *val |= (i2c_data & 0x3f) << 10; PDEBUG(D_V4L2, "Read exposure %d", *val); out: - return (err < 0) ? err : 0; + return err; } int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) @@ -253,24 +253,24 @@ int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) /* The 6 MSBs */ i2c_data = (val >> 10) & 0x3f; - err = ov9650_write_sensor(sd, OV9650_AECHM, + err = m5602_write_sensor(sd, OV9650_AECHM, &i2c_data, 1); if (err < 0) goto out; /* The 8 middle bits */ i2c_data = (val >> 2) & 0xff; - err = ov9650_write_sensor(sd, OV9650_AECH, + err = m5602_write_sensor(sd, OV9650_AECH, &i2c_data, 1); if (err < 0) goto out; /* The 2 LSBs */ i2c_data = val & 0x03; - err = ov9650_write_sensor(sd, OV9650_COM1, &i2c_data, 1); + err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1); out: - return (err < 0) ? err : 0; + return err; } int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) @@ -279,13 +279,13 @@ int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1); + m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); *val = (i2c_data & 0x03) << 8; - err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1); *val |= i2c_data; PDEBUG(D_V4L2, "Read gain %d", *val); - return (err < 0) ? err : 0; + return err; } int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) @@ -297,16 +297,16 @@ int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) /* The 2 MSB */ /* Read the OV9650_VREF register first to avoid corrupting the VREF high and low bits */ - ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1); + m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); /* Mask away all uninteresting bits */ i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F); - err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1); + err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1); /* The 8 LSBs */ i2c_data = val & 0xff; - err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); - return (err < 0) ? err : 0; + err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); + return err; } int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) @@ -315,12 +315,12 @@ int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - err = ov9650_read_sensor(sd, OV9650_RED, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_RED, &i2c_data, 1); *val = i2c_data; PDEBUG(D_V4L2, "Read red gain %d", *val); - return (err < 0) ? err : 0; + return err; } int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) @@ -333,9 +333,9 @@ int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) val & 0xff); i2c_data = val & 0xff; - err = ov9650_write_sensor(sd, OV9650_RED, &i2c_data, 1); + err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1); - return (err < 0) ? err : 0; + return err; } int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) @@ -344,12 +344,12 @@ int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - err = ov9650_read_sensor(sd, OV9650_BLUE, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_BLUE, &i2c_data, 1); *val = i2c_data; PDEBUG(D_V4L2, "Read blue gain %d", *val); - return (err < 0) ? err : 0; + return err; } int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) @@ -362,9 +362,9 @@ int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) val & 0xff); i2c_data = val & 0xff; - err = ov9650_write_sensor(sd, OV9650_BLUE, &i2c_data, 1); + err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1); - return (err < 0) ? err : 0; + return err; } int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -373,14 +373,14 @@ int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); if (dmi_check_system(ov9650_flip_dmi_table)) *val = ((i2c_data & OV9650_HFLIP) >> 5) ? 0 : 1; else *val = (i2c_data & OV9650_HFLIP) >> 5; PDEBUG(D_V4L2, "Read horizontal flip %d", *val); - return (err < 0) ? err : 0; + return err; } int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) @@ -390,20 +390,20 @@ int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; PDEBUG(D_V4L2, "Set horizontal flip to %d", val); - err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); if (err < 0) goto out; if (dmi_check_system(ov9650_flip_dmi_table)) i2c_data = ((i2c_data & 0xdf) | - (((val ? 0 : 1) & 0x01) << 5)); + (((val ? 0 : 1) & 0x01) << 5)); else i2c_data = ((i2c_data & 0xdf) | - ((val & 0x01) << 5)); + ((val & 0x01) << 5)); - err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); + err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); out: - return (err < 0) ? err : 0; + return err; } int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -412,14 +412,14 @@ int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); if (dmi_check_system(ov9650_flip_dmi_table)) *val = ((i2c_data & 0x10) >> 4) ? 0 : 1; else *val = (i2c_data & 0x10) >> 4; PDEBUG(D_V4L2, "Read vertical flip %d", *val); - return (err < 0) ? err : 0; + return err; } int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) @@ -429,7 +429,7 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; PDEBUG(D_V4L2, "Set vertical flip to %d", val); - err = ov9650_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1); if (err < 0) goto out; @@ -440,9 +440,9 @@ int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val) i2c_data = ((i2c_data & 0xef) | ((val & 0x01) << 4)); - err = ov9650_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); + err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); out: - return (err < 0) ? err : 0; + return err; } int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) @@ -451,16 +451,16 @@ int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); if (err < 0) goto out; *val = (i2c_data & 0x03) << 8; - err = ov9650_read_sensor(sd, OV9650_GAIN, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1); *val |= i2c_data; PDEBUG(D_V4L2, "Read gain %d", *val); out: - return (err < 0) ? err : 0; + return err; } int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val) @@ -473,22 +473,22 @@ int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val) /* Read the OV9650_VREF register first to avoid corrupting the VREF high and low bits */ - err = ov9650_read_sensor(sd, OV9650_VREF, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1); if (err < 0) goto out; /* Mask away all uninteresting bits */ i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F); - err = ov9650_write_sensor(sd, OV9650_VREF, &i2c_data, 1); + err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1); if (err < 0) goto out; /* The 8 LSBs */ i2c_data = val & 0xff; - err = ov9650_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); + err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1); out: - return (err < 0) ? err : 0; + return err; } int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val) @@ -497,11 +497,11 @@ int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); *val = (i2c_data & OV9650_AWB_EN) >> 1; PDEBUG(D_V4L2, "Read auto white balance %d", *val); - return (err < 0) ? err : 0; + return err; } int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) @@ -511,14 +511,14 @@ int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; PDEBUG(D_V4L2, "Set auto white balance to %d", val); - err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); if (err < 0) goto out; i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1)); - err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1); + err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); out: - return (err < 0) ? err : 0; + return err; } int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) @@ -527,11 +527,11 @@ int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; struct sd *sd = (struct sd *) gspca_dev; - err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); *val = (i2c_data & OV9650_AGC_EN) >> 2; PDEBUG(D_V4L2, "Read auto gain control %d", *val); - return (err < 0) ? err : 0; + return err; } int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) @@ -541,23 +541,23 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; PDEBUG(D_V4L2, "Set auto gain control to %d", val); - err = ov9650_read_sensor(sd, OV9650_COM8, &i2c_data, 1); + err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); if (err < 0) goto out; i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2)); - err = ov9650_write_sensor(sd, OV9650_COM8, &i2c_data, 1); + err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); out: - return (err < 0) ? err : 0; + return err; } -void ov9650_dump_registers(struct sd *sd) +static void ov9650_dump_registers(struct sd *sd) { int address; info("Dumping the ov9650 register state"); for (address = 0; address < 0xa9; address++) { u8 value; - ov9650_read_sensor(sd, address, &value, 1); + m5602_read_sensor(sd, address, &value, 1); info("register 0x%x contains 0x%x", address, value); } @@ -569,9 +569,9 @@ void ov9650_dump_registers(struct sd *sd) u8 old_value, ctrl_value; u8 test_value[2] = {0xff, 0xff}; - ov9650_read_sensor(sd, address, &old_value, 1); - ov9650_write_sensor(sd, address, test_value, 1); - ov9650_read_sensor(sd, address, &ctrl_value, 1); + m5602_read_sensor(sd, address, &old_value, 1); + m5602_write_sensor(sd, address, test_value, 1); + m5602_read_sensor(sd, address, &ctrl_value, 1); if (ctrl_value == test_value[0]) info("register 0x%x is writeable", address); @@ -579,6 +579,6 @@ void ov9650_dump_registers(struct sd *sd) info("register 0x%x is read only", address); /* Restore original value */ - ov9650_write_sensor(sd, address, &old_value, 1); + m5602_write_sensor(sd, address, &old_value, 1); } } diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h index e0efdb930..f4b33b8e8 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h +++ b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h @@ -20,7 +20,6 @@ #define M5602_OV9650_H_ #include <linux/dmi.h> - #include "m5602_sensor.h" /*****************************************************************************/ @@ -36,6 +35,7 @@ #define OV9650_PID 0x0a #define OV9650_VER 0x0b #define OV9650_COM3 0x0c +#define OV9650_COM4 0x0d #define OV9650_COM5 0x0e #define OV9650_COM6 0x0f #define OV9650_AECH 0x10 @@ -94,6 +94,8 @@ #define OV9650_REGISTER_RESET (1 << 7) #define OV9650_VGA_SELECT (1 << 6) +#define OV9650_CIF_SELECT (1 << 5) +#define OV9650_QVGA_SELECT (1 << 4) #define OV9650_RGB_SELECT (1 << 2) #define OV9650_RAW_RGB_SELECT (1 << 0) @@ -108,6 +110,8 @@ #define OV9650_SYSTEM_CLK_SEL (1 << 7) #define OV9650_SLAM_MODE (1 << 4) +#define OV9650_QVGA_VARIOPIXEL (1 << 7) + #define OV9650_VFLIP (1 << 4) #define OV9650_HFLIP (1 << 5) @@ -124,15 +128,9 @@ extern int dump_sensor; int ov9650_probe(struct sd *sd); int ov9650_init(struct sd *sd); +int ov9650_start(struct sd *sd); int ov9650_power_down(struct sd *sd); -int ov9650_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); -int ov9650_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - -void ov9650_dump_registers(struct sd *sd); - int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val); int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val); @@ -155,11 +153,11 @@ int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val); static struct m5602_sensor ov9650 = { .name = "OV9650", .i2c_slave_id = 0x60, + .i2c_regW = 1, .probe = ov9650_probe, .init = ov9650_init, + .start = ov9650_start, .power_down = ov9650_power_down, - .read_sensor = ov9650_read_sensor, - .write_sensor = ov9650_write_sensor, .nctrls = 8, .ctrls = { @@ -264,18 +262,38 @@ static struct m5602_sensor ov9650 = { } }, - .nmodes = 1, + .nmodes = 3, .modes = { { - M5602_DEFAULT_FRAME_WIDTH, - M5602_DEFAULT_FRAME_HEIGHT, + 320, + 240, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 320 * 240, + .bytesperline = 320, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + }, { + 352, + 288, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .sizeimage = - M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT, - .bytesperline = M5602_DEFAULT_FRAME_WIDTH, + 352 * 288, + .bytesperline = 352, .colorspace = V4L2_COLORSPACE_SRGB, - .priv = 1 + .priv = 0 + }, { + 640, + 480, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + 640 * 480, + .bytesperline = 640, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 } } }; @@ -324,6 +342,7 @@ static const unsigned char init_ov9650[][3] = {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00}, {BRIDGE, M5602_XB_GPIO_DAT, 0x00}, {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a}, + /* Reset chip */ {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET}, /* Enable double clock */ @@ -331,8 +350,6 @@ static const unsigned char init_ov9650[][3] = /* Do something out of spec with the power */ {SENSOR, OV9650_OFON, 0x40}, - /* Set QQVGA */ - {SENSOR, OV9650_COM1, 0x20}, /* Set fast AGC/AEC algorithm with unlimited step size */ {SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC | OV9650_AEC_UNLIM_STEP_SIZE | @@ -343,7 +360,7 @@ static const unsigned char init_ov9650[][3] = {SENSOR, OV9650_ACOM38, 0x81}, /* Turn off color matrix coefficient double option */ {SENSOR, OV9650_COM16, 0x00}, - /* Enable color matrix for RGB/YUV, Delay Y channel, + /* Enable color matrix for RGB/YUV, Delay Y channel, set output Y/UV delay to 1 */ {SENSOR, OV9650_COM13, 0x19}, /* Enable digital BLC, Set output mode to U Y V Y */ @@ -352,7 +369,7 @@ static const unsigned char init_ov9650[][3] = {SENSOR, OV9650_COM24, 0x00}, /* Enable HREF and some out of spec things */ {SENSOR, OV9650_COM12, 0x73}, - /* Set all DBLC offset signs to positive and + /* Set all DBLC offset signs to positive and do some out of spec stuff */ {SENSOR, OV9650_DBLC1, 0xdf}, {SENSOR, OV9650_COM21, 0x06}, @@ -364,7 +381,7 @@ static const unsigned char init_ov9650[][3] = {SENSOR, OV9650_RSVD96, 0x04}, /* Enable full range output */ {SENSOR, OV9650_COM15, 0x0}, - /* Enable HREF at optical black, enable ADBLC bias, + /* Enable HREF at optical black, enable ADBLC bias, enable ADBLC, reset timings at format change */ {SENSOR, OV9650_COM6, 0x4b}, /* Subtract 32 from the B channel bias */ @@ -385,7 +402,7 @@ static const unsigned char init_ov9650[][3] = {SENSOR, OV9650_AEB, 0x5c}, /* Set the high and low limit nibbles to 3 */ {SENSOR, OV9650_VPT, 0xc3}, - /* Set the Automatic Gain Ceiling (AGC) to 128x, + /* Set the Automatic Gain Ceiling (AGC) to 128x, drop VSYNC at frame drop, limit exposure timing, drop frame when the AEC step is larger than the exposure gap */ @@ -394,9 +411,9 @@ static const unsigned char init_ov9650[][3] = and set PWDN to SLVS (slave mode vertical sync) */ {SENSOR, OV9650_COM10, 0x42}, /* Set horizontal column start high to default value */ - {SENSOR, OV9650_HSTART, 0x1a}, + {SENSOR, OV9650_HSTART, 0x1a}, /* 210 */ /* Set horizontal column end */ - {SENSOR, OV9650_HSTOP, 0xbf}, + {SENSOR, OV9650_HSTOP, 0xbf}, /* 1534 */ /* Complementing register to the two writes above */ {SENSOR, OV9650_HREF, 0xb2}, /* Set vertical row start high bits */ @@ -405,10 +422,6 @@ static const unsigned char init_ov9650[][3] = {SENSOR, OV9650_VSTOP, 0x7e}, /* Set complementing vertical frame control */ {SENSOR, OV9650_VREF, 0x10}, - /* Set raw RGB output format with VGA resolution */ - {SENSOR, OV9650_COM7, OV9650_VGA_SELECT | - OV9650_RGB_SELECT | - OV9650_RAW_RGB_SELECT}, {SENSOR, OV9650_ADC, 0x04}, {SENSOR, OV9650_HV, 0x40}, /* Enable denoise, and white-pixel erase */ @@ -417,31 +430,15 @@ static const unsigned char init_ov9650[][3] = /* Set the high bits of the exposure value */ {SENSOR, OV9650_AECH, ((EXPOSURE_DEFAULT & 0xff00) >> 8)}, + /* Enable VARIOPIXEL */ + {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL}, + {SENSOR, OV9650_COM4, OV9650_QVGA_VARIOPIXEL}, + /* Set the low bits of the exposure value */ {SENSOR, OV9650_COM1, (EXPOSURE_DEFAULT & 0xff)}, {SENSOR, OV9650_GAIN, GAIN_DEFAULT}, {SENSOR, OV9650_BLUE, BLUE_GAIN_DEFAULT}, {SENSOR, OV9650_RED, RED_GAIN_DEFAULT}, - - {SENSOR, OV9650_COM3, OV9650_VARIOPIXEL}, - {SENSOR, OV9650_COM5, OV9650_SYSTEM_CLK_SEL}, - - {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82}, - {BRIDGE, M5602_XB_LINE_OF_FRAME_L, 0x00}, - {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82}, - {BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00}, - {BRIDGE, M5602_XB_SIG_INI, 0x01}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - /* Moves the view window in a vertical orientation */ - {BRIDGE, M5602_XB_VSYNC_PARA, 0x09}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, - {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x5e}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, - {BRIDGE, M5602_XB_HSYNC_PARA, 0xde} }; static const unsigned char power_down_ov9650[][3] = @@ -461,7 +458,76 @@ static const unsigned char power_down_ov9650[][3] = {BRIDGE, M5602_XB_GPIO_EN_L, 0x06}, {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02}, {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04}, - {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0} + {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}, +}; + +static const unsigned char res_init_ov9650[][2] = +{ + {M5602_XB_LINE_OF_FRAME_H, 0x82}, + {M5602_XB_LINE_OF_FRAME_L, 0x00}, + {M5602_XB_PIX_OF_LINE_H, 0x82}, + {M5602_XB_PIX_OF_LINE_L, 0x00}, + {M5602_XB_SIG_INI, 0x01} +}; + +static const unsigned char VGA_ov9650[][3] = +{ + /* Moves the view window in a vertical orientation */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x09}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, /* 480 */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x62}, /* 98 */ + {BRIDGE, M5602_XB_HSYNC_PARA, 0x02}, /* 640 + 98 */ + {BRIDGE, M5602_XB_HSYNC_PARA, 0xe2}, + + {SENSOR, OV9650_COM7, OV9650_VGA_SELECT | + OV9650_RGB_SELECT | + OV9650_RAW_RGB_SELECT}, +}; + +static const unsigned char CIF_ov9650[][3] = +{ + /* Moves the view window in a vertical orientation */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x09}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x01}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x20}, /* 288 */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x62}, /* 98 */ + {BRIDGE, M5602_XB_HSYNC_PARA, 0x01}, /* 352 + 98 */ + {BRIDGE, M5602_XB_HSYNC_PARA, 0xc2}, + + {SENSOR, OV9650_COM7, OV9650_CIF_SELECT | + OV9650_RGB_SELECT | + OV9650_RAW_RGB_SELECT}, +}; + +static const unsigned char QVGA_ov9650[][3] = +{ + /* Moves the view window in a vertical orientation */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x08}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0xf0}, /* 240 */ + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_VSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x00}, + {BRIDGE, M5602_XB_HSYNC_PARA, 0x31}, /* 50 */ + {BRIDGE, M5602_XB_HSYNC_PARA, 0x01}, /* 320 + 50 */ + {BRIDGE, M5602_XB_HSYNC_PARA, 0x71}, + + {SENSOR, OV9650_COM7, OV9650_QVGA_SELECT | + OV9650_RGB_SELECT | + OV9650_RAW_RGB_SELECT}, }; #endif diff --git a/linux/drivers/media/video/gspca/m5602/m5602_po1030.c b/linux/drivers/media/video/gspca/m5602/m5602_po1030.c index d17ac5256..2e7fb9167 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_po1030.c +++ b/linux/drivers/media/video/gspca/m5602/m5602_po1030.c @@ -18,6 +18,8 @@ #include "m5602_po1030.h" +static void po1030_dump_registers(struct sd *sd); + int po1030_probe(struct sd *sd) { u8 prod_id = 0, ver_id = 0, i; @@ -38,16 +40,16 @@ int po1030_probe(struct sd *sd) for (i = 0; i < ARRAY_SIZE(preinit_po1030); i++) { u8 data = preinit_po1030[i][2]; if (preinit_po1030[i][0] == SENSOR) - po1030_write_sensor(sd, + m5602_write_sensor(sd, preinit_po1030[i][1], &data, 1); else m5602_write_bridge(sd, preinit_po1030[i][1], data); } - if (po1030_read_sensor(sd, 0x3, &prod_id, 1)) + if (m5602_read_sensor(sd, 0x3, &prod_id, 1)) return -ENODEV; - if (po1030_read_sensor(sd, 0x4, &ver_id, 1)) + if (m5602_read_sensor(sd, 0x4, &ver_id, 1)) return -ENODEV; if ((prod_id == 0x02) && (ver_id == 0xef)) { @@ -64,78 +66,12 @@ sensor_found: return 0; } -int po1030_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) -{ - int err, i; - - do { - err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); - } while ((*i2c_data & I2C_BUSY) && !err); - - m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, - sd->sensor->i2c_slave_id); - m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); - m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x10 + len); - m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x08); - - for (i = 0; i < len; i++) { - err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); - - PDEBUG(D_CONF, "Reading sensor register " - "0x%x containing 0x%x ", address, *i2c_data); - } - return (err < 0) ? err : 0; -} - -int po1030_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) -{ - int err, i; - u8 *p; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - /* The po1030 only supports one byte writes */ - if (len > 1 || !len) - return -EINVAL; - - memcpy(buf, sensor_urb_skeleton, sizeof(sensor_urb_skeleton)); - - buf[11] = sd->sensor->i2c_slave_id; - buf[15] = address; - - p = buf + 16; - - /* Copy a four byte write sequence for each byte to be written to */ - for (i = 0; i < len; i++) { - memcpy(p, sensor_urb_skeleton + 16, 4); - p[3] = i2c_data[i]; - p += 4; - PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x", - address, i2c_data[i]); - } - - /* Copy the footer */ - memcpy(p, sensor_urb_skeleton + 20, 4); - - /* Set the total length */ - p[3] = 0x10 + len; - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, 0x19, - 0x0000, buf, - 20 + len * 4, M5602_URB_MSG_TIMEOUT); - - return (err < 0) ? err : 0; -} - int po1030_init(struct sd *sd) { int i, err = 0; /* Init the sensor */ - for (i = 0; i < ARRAY_SIZE(init_po1030); i++) { + for (i = 0; i < ARRAY_SIZE(init_po1030) && !err; i++) { u8 data[2] = {0x00, 0x00}; switch (init_po1030[i][0]) { @@ -147,16 +83,10 @@ int po1030_init(struct sd *sd) case SENSOR: data[0] = init_po1030[i][2]; - err = po1030_write_sensor(sd, + err = m5602_write_sensor(sd, init_po1030[i][1], data, 1); break; - case SENSOR_LONG: - data[0] = init_po1030[i][2]; - data[1] = init_po1030[i][3]; - err = po1030_write_sensor(sd, - init_po1030[i][1], data, 2); - break; default: info("Invalid stream command, exiting init"); return -EINVAL; @@ -166,7 +96,7 @@ int po1030_init(struct sd *sd) if (dump_sensor) po1030_dump_registers(sd); - return (err < 0) ? err : 0; + return err; } int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) @@ -175,19 +105,19 @@ int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; int err; - err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_H, + err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_H, &i2c_data, 1); if (err < 0) goto out; *val = (i2c_data << 8); - err = po1030_read_sensor(sd, PO1030_REG_INTEGLINES_M, + err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_M, &i2c_data, 1); *val |= i2c_data; PDEBUG(D_V4L2, "Exposure read as %d", *val); out: - return (err < 0) ? err : 0; + return err; } int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) @@ -202,7 +132,7 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x", i2c_data); - err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_H, + err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_H, &i2c_data, 1); if (err < 0) goto out; @@ -210,11 +140,11 @@ int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) i2c_data = (val & 0xff); PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x", i2c_data); - err = po1030_write_sensor(sd, PO1030_REG_INTEGLINES_M, + err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_M, &i2c_data, 1); out: - return (err < 0) ? err : 0; + return err; } int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val) @@ -223,12 +153,12 @@ int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; int err; - err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN, + err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN, &i2c_data, 1); *val = i2c_data; PDEBUG(D_V4L2, "Read global gain %d", *val); - return (err < 0) ? err : 0; + return err; } int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -237,14 +167,14 @@ int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; int err; - err = po1030_read_sensor(sd, PO1030_REG_CONTROL2, + err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1); *val = (i2c_data >> 7) & 0x01 ; PDEBUG(D_V4L2, "Read hflip %d", *val); - return (err < 0) ? err : 0; + return err; } int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val) @@ -254,13 +184,17 @@ int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val) int err; PDEBUG(D_V4L2, "Set hflip %d", val); + err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1); + if (err < 0) + goto out; - i2c_data = (val & 0x01) << 7; + i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7); - err = po1030_write_sensor(sd, PO1030_REG_CONTROL2, - &i2c_data, 1); + err = m5602_write_sensor(sd, PO1030_REG_CONTROL2, + &i2c_data, 1); - return (err < 0) ? err : 0; +out: + return err; } int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -269,14 +203,14 @@ int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; int err; - err = po1030_read_sensor(sd, PO1030_REG_GLOBALGAIN, + err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN, &i2c_data, 1); *val = (i2c_data >> 6) & 0x01; PDEBUG(D_V4L2, "Read vflip %d", *val); - return (err < 0) ? err : 0; + return err; } int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val) @@ -286,13 +220,17 @@ int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val) int err; PDEBUG(D_V4L2, "Set vflip %d", val); + err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1); + if (err < 0) + goto out; - i2c_data = (val & 0x01) << 6; + i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6); - err = po1030_write_sensor(sd, PO1030_REG_CONTROL2, - &i2c_data, 1); + err = m5602_write_sensor(sd, PO1030_REG_CONTROL2, + &i2c_data, 1); - return (err < 0) ? err : 0; +out: + return err; } int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) @@ -303,9 +241,9 @@ int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) i2c_data = val & 0xff; PDEBUG(D_V4L2, "Set global gain to %d", i2c_data); - err = po1030_write_sensor(sd, PO1030_REG_GLOBALGAIN, + err = m5602_write_sensor(sd, PO1030_REG_GLOBALGAIN, &i2c_data, 1); - return (err < 0) ? err : 0; + return err; } int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) @@ -314,11 +252,11 @@ int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; int err; - err = po1030_read_sensor(sd, PO1030_REG_RED_GAIN, + err = m5602_read_sensor(sd, PO1030_REG_RED_GAIN, &i2c_data, 1); *val = i2c_data; PDEBUG(D_V4L2, "Read red gain %d", *val); - return (err < 0) ? err : 0; + return err; } int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) @@ -329,9 +267,9 @@ int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) i2c_data = val & 0xff; PDEBUG(D_V4L2, "Set red gain to %d", i2c_data); - err = po1030_write_sensor(sd, PO1030_REG_RED_GAIN, + err = m5602_write_sensor(sd, PO1030_REG_RED_GAIN, &i2c_data, 1); - return (err < 0) ? err : 0; + return err; } int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) @@ -340,12 +278,12 @@ int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) u8 i2c_data; int err; - err = po1030_read_sensor(sd, PO1030_REG_BLUE_GAIN, + err = m5602_read_sensor(sd, PO1030_REG_BLUE_GAIN, &i2c_data, 1); *val = i2c_data; PDEBUG(D_V4L2, "Read blue gain %d", *val); - return (err < 0) ? err : 0; + return err; } int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) @@ -355,10 +293,10 @@ int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) int err; i2c_data = val & 0xff; PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data); - err = po1030_write_sensor(sd, PO1030_REG_BLUE_GAIN, + err = m5602_write_sensor(sd, PO1030_REG_BLUE_GAIN, &i2c_data, 1); - return (err < 0) ? err : 0; + return err; } int po1030_power_down(struct sd *sd) @@ -366,14 +304,14 @@ int po1030_power_down(struct sd *sd) return 0; } -void po1030_dump_registers(struct sd *sd) +static void po1030_dump_registers(struct sd *sd) { int address; u8 value = 0; info("Dumping the po1030 sensor core registers"); for (address = 0; address < 0x7f; address++) { - po1030_read_sensor(sd, address, &value, 1); + m5602_read_sensor(sd, address, &value, 1); info("register 0x%x contains 0x%x", address, value); } @@ -385,9 +323,9 @@ void po1030_dump_registers(struct sd *sd) u8 old_value, ctrl_value; u8 test_value[2] = {0xff, 0xff}; - po1030_read_sensor(sd, address, &old_value, 1); - po1030_write_sensor(sd, address, test_value, 1); - po1030_read_sensor(sd, address, &ctrl_value, 1); + m5602_read_sensor(sd, address, &old_value, 1); + m5602_write_sensor(sd, address, test_value, 1); + m5602_read_sensor(sd, address, &ctrl_value, 1); if (ctrl_value == test_value[0]) info("register 0x%x is writeable", address); @@ -395,6 +333,6 @@ void po1030_dump_registers(struct sd *sd) info("register 0x%x is read only", address); /* Restore original value */ - po1030_write_sensor(sd, address, &old_value, 1); + m5602_write_sensor(sd, address, &old_value, 1); } } diff --git a/linux/drivers/media/video/gspca/m5602/m5602_po1030.h b/linux/drivers/media/video/gspca/m5602/m5602_po1030.h index a0b75ff61..def39d5bc 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_po1030.h +++ b/linux/drivers/media/video/gspca/m5602/m5602_po1030.h @@ -10,7 +10,7 @@ * v4l2 interface modeled after the V4L2 driver * for SN9C10x PC Camera Controllers * - * Register defines taken from Pascal Stangs Proxycon Armlib + * Register defines taken from Pascal Stangs Procyon Armlib * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -128,13 +128,6 @@ int po1030_probe(struct sd *sd); int po1030_init(struct sd *sd); int po1030_power_down(struct sd *sd); -void po1030_dump_registers(struct sd *sd); - -int po1030_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); -int po1030_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val); int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val); @@ -152,6 +145,7 @@ static struct m5602_sensor po1030 = { .name = "PO1030", .i2c_slave_id = 0xdc, + .i2c_regW = 1, .probe = po1030_probe, .init = po1030_init, diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c index 1f72e7eae..2bd7d4d99 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c +++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c @@ -52,6 +52,7 @@ static { } }; +static void s5k4aa_dump_registers(struct sd *sd); int s5k4aa_probe(struct sd *sd) { @@ -84,7 +85,7 @@ int s5k4aa_probe(struct sd *sd) case SENSOR: data[0] = preinit_s5k4aa[i][2]; - err = s5k4aa_write_sensor(sd, + err = m5602_write_sensor(sd, preinit_s5k4aa[i][1], data, 1); break; @@ -92,7 +93,7 @@ int s5k4aa_probe(struct sd *sd) case SENSOR_LONG: data[0] = preinit_s5k4aa[i][2]; data[1] = preinit_s5k4aa[i][3]; - err = s5k4aa_write_sensor(sd, + err = m5602_write_sensor(sd, preinit_s5k4aa[i][1], data, 2); break; @@ -103,13 +104,14 @@ int s5k4aa_probe(struct sd *sd) } /* Test some registers, but we don't know their exact meaning yet */ - if (s5k4aa_read_sensor(sd, 0x00, prod_id, sizeof(prod_id))) + if (m5602_read_sensor(sd, 0x00, prod_id, sizeof(prod_id))) return -ENODEV; if (memcmp(prod_id, expected_prod_id, sizeof(prod_id))) return -ENODEV; else info("Detected a s5k4aa sensor"); + sensor_found: sd->gspca_dev.cam.cam_mode = s5k4aa.modes; sd->gspca_dev.cam.nmodes = s5k4aa.nmodes; @@ -119,90 +121,6 @@ sensor_found: return 0; } -int s5k4aa_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) -{ - int err, i; - - do { - err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); - } while ((*i2c_data & I2C_BUSY) && !err); - if (err < 0) - goto out; - - err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, - sd->sensor->i2c_slave_id); - if (err < 0) - goto out; - - err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); - if (err < 0) - goto out; - - err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len); - if (err < 0) - goto out; - - do { - err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); - } while ((*i2c_data & I2C_BUSY) && !err); - if (err < 0) - goto out; - - for (i = 0; (i < len) & !err; i++) { - err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); - - PDEBUG(D_CONF, "Reading sensor register " - "0x%x containing 0x%x ", address, *i2c_data); - } -out: - return (err < 0) ? err : 0; -} - -int s5k4aa_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) -{ - int err, i; - u8 *p; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - /* No sensor with a data width larger than 16 bits has yet been seen */ - if (len > 2 || !len) - return -EINVAL; - - memcpy(buf, sensor_urb_skeleton, - sizeof(sensor_urb_skeleton)); - - buf[11] = sd->sensor->i2c_slave_id; - buf[15] = address; - - /* Special case larger sensor writes */ - p = buf + 16; - - /* Copy a four byte write sequence for each byte to be written to */ - for (i = 0; i < len; i++) { - memcpy(p, sensor_urb_skeleton + 16, 4); - p[3] = i2c_data[i]; - p += 4; - PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x", - address, i2c_data[i]); - } - - /* Copy the tailer */ - memcpy(p, sensor_urb_skeleton + 20, 4); - - /* Set the total length */ - p[3] = 0x10 + len; - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, 0x19, - 0x0000, buf, - 20 + len * 4, M5602_URB_MSG_TIMEOUT); - - return (err < 0) ? err : 0; -} - int s5k4aa_init(struct sd *sd) { int i, err = 0; @@ -219,14 +137,14 @@ int s5k4aa_init(struct sd *sd) case SENSOR: data[0] = init_s5k4aa[i][2]; - err = s5k4aa_write_sensor(sd, + err = m5602_write_sensor(sd, init_s5k4aa[i][1], data, 1); break; case SENSOR_LONG: data[0] = init_s5k4aa[i][2]; data[1] = init_s5k4aa[i][3]; - err = s5k4aa_write_sensor(sd, + err = m5602_write_sensor(sd, init_s5k4aa[i][1], data, 2); break; default: @@ -241,21 +159,21 @@ int s5k4aa_init(struct sd *sd) if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) { u8 data = 0x02; info("vertical flip quirk active"); - s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); - s5k4aa_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); + m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1); data |= S5K4AA_RM_V_FLIP; data &= ~S5K4AA_RM_H_FLIP; - s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); /* Decrement COLSTART to preserve color order (BGGR) */ - s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); data--; - s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); /* Increment ROWSTART to preserve color order (BGGR) */ - s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); data++; - s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); } return (err < 0) ? err : 0; @@ -272,20 +190,20 @@ int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) u8 data = S5K4AA_PAGE_MAP_2; int err; - err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) goto out; - err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); if (err < 0) goto out; *val = data << 8; - err = s5k4aa_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); *val |= data; PDEBUG(D_V4L2, "Read exposure %d", *val); out: - return (err < 0) ? err : 0; + return err; } int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) @@ -295,17 +213,17 @@ int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) int err; PDEBUG(D_V4L2, "Set exposure to %d", val); - err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) goto out; data = (val >> 8) & 0xff; - err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1); if (err < 0) goto out; data = val & 0xff; - err = s5k4aa_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1); out: - return (err < 0) ? err : 0; + return err; } int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -314,16 +232,16 @@ int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) u8 data = S5K4AA_PAGE_MAP_2; int err; - err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) goto out; - err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); *val = (data & S5K4AA_RM_V_FLIP) >> 7; PDEBUG(D_V4L2, "Read vertical flip %d", *val); out: - return (err < 0) ? err : 0; + return err; } int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) @@ -333,35 +251,35 @@ int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val) int err; PDEBUG(D_V4L2, "Set vertical flip to %d", val); - err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) goto out; - err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); if (err < 0) goto out; data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7)); - err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); if (err < 0) goto out; if (val) { - err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); if (err < 0) goto out; data++; - err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); } else { - err = s5k4aa_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); if (err < 0) goto out; data--; - err = s5k4aa_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1); } out: - return (err < 0) ? err : 0; + return err; } int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -370,15 +288,15 @@ int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) u8 data = S5K4AA_PAGE_MAP_2; int err; - err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) goto out; - err = s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); *val = (data & S5K4AA_RM_H_FLIP) >> 6; PDEBUG(D_V4L2, "Read horizontal flip %d", *val); out: - return (err < 0) ? err : 0; + return err; } int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) @@ -389,35 +307,35 @@ int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val) PDEBUG(D_V4L2, "Set horizontal flip to %d", val); - err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) goto out; - err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); if (err < 0) goto out; data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6)); - err = s5k4aa_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); if (err < 0) goto out; if (val) { - err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); if (err < 0) goto out; data++; - err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); if (err < 0) goto out; } else { - err = s5k4aa_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); if (err < 0) goto out; data--; - err = s5k4aa_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); } out: - return (err < 0) ? err : 0; + return err; } int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val) @@ -426,16 +344,16 @@ int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val) u8 data = S5K4AA_PAGE_MAP_2; int err; - err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) goto out; - err = s5k4aa_read_sensor(sd, S5K4AA_GAIN_2, &data, 1); + err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1); *val = data; PDEBUG(D_V4L2, "Read gain %d", *val); out: - return (err < 0) ? err : 0; + return err; } int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) @@ -445,28 +363,28 @@ int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) int err; PDEBUG(D_V4L2, "Set gain to %d", val); - err = s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); if (err < 0) goto out; data = val & 0xff; - err = s5k4aa_write_sensor(sd, S5K4AA_GAIN_2, &data, 1); + err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1); out: - return (err < 0) ? err : 0; + return err; } -void s5k4aa_dump_registers(struct sd *sd) +static void s5k4aa_dump_registers(struct sd *sd) { int address; u8 page, old_page; - s5k4aa_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); + m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); for (page = 0; page < 16; page++) { - s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); + m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); info("Dumping the s5k4aa register state for page 0x%x", page); for (address = 0; address <= 0xff; address++) { u8 value = 0; - s5k4aa_read_sensor(sd, address, &value, 1); + m5602_read_sensor(sd, address, &value, 1); info("register 0x%x contains 0x%x", address, value); } @@ -474,15 +392,15 @@ void s5k4aa_dump_registers(struct sd *sd) info("s5k4aa register state dump complete"); for (page = 0; page < 16; page++) { - s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); + m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &page, 1); info("Probing for which registers that are " "read/write for page 0x%x", page); for (address = 0; address <= 0xff; address++) { u8 old_value, ctrl_value, test_value = 0xff; - s5k4aa_read_sensor(sd, address, &old_value, 1); - s5k4aa_write_sensor(sd, address, &test_value, 1); - s5k4aa_read_sensor(sd, address, &ctrl_value, 1); + m5602_read_sensor(sd, address, &old_value, 1); + m5602_write_sensor(sd, address, &test_value, 1); + m5602_read_sensor(sd, address, &ctrl_value, 1); if (ctrl_value == test_value) info("register 0x%x is writeable", address); @@ -490,9 +408,9 @@ void s5k4aa_dump_registers(struct sd *sd) info("register 0x%x is read only", address); /* Restore original value */ - s5k4aa_write_sensor(sd, address, &old_value, 1); + m5602_write_sensor(sd, address, &old_value, 1); } } info("Read/write register probing complete"); - s5k4aa_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); + m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &old_page, 1); } diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h index 151c6f530..1f88b0d04 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h +++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h @@ -41,11 +41,10 @@ #define S5K4AA_WINDOW_HEIGHT_LO 0x09 #define S5K4AA_WINDOW_WIDTH_HI 0x0a #define S5K4AA_WINDOW_WIDTH_LO 0x0b -#define S5K4AA_GLOBAL_GAIN__ 0x0f /* Only a guess ATM !!! */ -#define S5K4AA_H_BLANK_HI__ 0x1d /* Only a guess ATM !!! sync lost - if too low, reduces frame rate - if too high */ -#define S5K4AA_H_BLANK_LO__ 0x1e /* Only a guess ATM !!! */ +#define S5K4AA_GLOBAL_GAIN__ 0x0f +/* sync lost, if too low, reduces frame rate if too high */ +#define S5K4AA_H_BLANK_HI__ 0x1d +#define S5K4AA_H_BLANK_LO__ 0x1e #define S5K4AA_EXPOSURE_HI 0x17 #define S5K4AA_EXPOSURE_LO 0x18 #define S5K4AA_GAIN_1 0x1f /* (digital?) gain : 5 bits */ @@ -68,13 +67,6 @@ int s5k4aa_probe(struct sd *sd); int s5k4aa_init(struct sd *sd); int s5k4aa_power_down(struct sd *sd); -void s5k4aa_dump_registers(struct sd *sd); - -int s5k4aa_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); -int s5k4aa_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val); int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); @@ -89,9 +81,8 @@ static struct m5602_sensor s5k4aa = { .probe = s5k4aa_probe, .init = s5k4aa_init, .power_down = s5k4aa_power_down, - .read_sensor = s5k4aa_read_sensor, - .write_sensor = s5k4aa_write_sensor, .i2c_slave_id = 0x5a, + .i2c_regW = 2, .nctrls = 4, .ctrls = { { diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c index 8988a728e..af3f2dc2c 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c +++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c @@ -18,6 +18,8 @@ #include "m5602_s5k83a.h" +static void s5k83a_dump_registers(struct sd *sd); + int s5k83a_probe(struct sd *sd) { u8 prod_id = 0, ver_id = 0; @@ -39,7 +41,7 @@ int s5k83a_probe(struct sd *sd) for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) { u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]}; if (preinit_s5k83a[i][0] == SENSOR) - err = s5k83a_write_sensor(sd, preinit_s5k83a[i][1], + err = m5602_write_sensor(sd, preinit_s5k83a[i][1], data, 2); else err = m5602_write_bridge(sd, preinit_s5k83a[i][1], @@ -49,10 +51,10 @@ int s5k83a_probe(struct sd *sd) /* We don't know what register (if any) that contain the product id * Just pick the first addresses that seem to produce the same results * on multiple machines */ - if (s5k83a_read_sensor(sd, 0x00, &prod_id, 1)) + if (m5602_read_sensor(sd, 0x00, &prod_id, 1)) return -ENODEV; - if (s5k83a_read_sensor(sd, 0x01, &ver_id, 1)) + if (m5602_read_sensor(sd, 0x01, &ver_id, 1)) return -ENODEV; if ((prod_id == 0xff) || (ver_id == 0xff)) @@ -68,91 +70,6 @@ sensor_found: return 0; } -int s5k83a_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) -{ - int err, i; - - do { - err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); - } while ((*i2c_data & I2C_BUSY) && !err); - if (err < 0) - goto out; - - err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR, - sd->sensor->i2c_slave_id); - if (err < 0) - goto out; - - err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address); - if (err < 0) - goto out; - - err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 0x18 + len); - if (err < 0) - goto out; - - do { - err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data); - } while ((*i2c_data & I2C_BUSY) && !err); - - if (err < 0) - goto out; - for (i = 0; i < len && !len; i++) { - err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); - - PDEBUG(D_CONF, "Reading sensor register " - "0x%x containing 0x%x ", address, *i2c_data); - } - -out: - return (err < 0) ? err : 0; -} - -int s5k83a_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len) -{ - int err, i; - u8 *p; - struct usb_device *udev = sd->gspca_dev.dev; - __u8 *buf = sd->gspca_dev.usb_buf; - - /* No sensor with a data width larger than 16 bits has yet been seen */ - if (len > 2 || !len) - return -EINVAL; - - memcpy(buf, sensor_urb_skeleton, - sizeof(sensor_urb_skeleton)); - - buf[11] = sd->sensor->i2c_slave_id; - buf[15] = address; - - /* Special case larger sensor writes */ - p = buf + 16; - - /* Copy a four byte write sequence for each byte to be written to */ - for (i = 0; i < len; i++) { - memcpy(p, sensor_urb_skeleton + 16, 4); - p[3] = i2c_data[i]; - p += 4; - PDEBUG(D_CONF, "Writing sensor register 0x%x with 0x%x", - address, i2c_data[i]); - } - - /* Copy the tailer */ - memcpy(p, sensor_urb_skeleton + 20, 4); - - /* Set the total length */ - p[3] = 0x10 + len; - - err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - 0x04, 0x40, 0x19, - 0x0000, buf, - 20 + len * 4, M5602_URB_MSG_TIMEOUT); - - return (err < 0) ? err : 0; -} - int s5k83a_init(struct sd *sd) { int i, err = 0; @@ -169,14 +86,14 @@ int s5k83a_init(struct sd *sd) case SENSOR: data[0] = init_s5k83a[i][2]; - err = s5k83a_write_sensor(sd, + err = m5602_write_sensor(sd, init_s5k83a[i][1], data, 1); break; case SENSOR_LONG: data[0] = init_s5k83a[i][2]; data[1] = init_s5k83a[i][3]; - err = s5k83a_write_sensor(sd, + err = m5602_write_sensor(sd, init_s5k83a[i][1], data, 2); break; default: @@ -200,14 +117,14 @@ void s5k83a_dump_registers(struct sd *sd) { int address; u8 page, old_page; - s5k83a_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); + m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); for (page = 0; page < 16; page++) { - s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); + m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); info("Dumping the s5k83a register state for page 0x%x", page); for (address = 0; address <= 0xff; address++) { u8 val = 0; - s5k83a_read_sensor(sd, address, &val, 1); + m5602_read_sensor(sd, address, &val, 1); info("register 0x%x contains 0x%x", address, val); } @@ -215,15 +132,15 @@ void s5k83a_dump_registers(struct sd *sd) info("s5k83a register state dump complete"); for (page = 0; page < 16; page++) { - s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); + m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); info("Probing for which registers that are read/write " "for page 0x%x", page); for (address = 0; address <= 0xff; address++) { u8 old_val, ctrl_val, test_val = 0xff; - s5k83a_read_sensor(sd, address, &old_val, 1); - s5k83a_write_sensor(sd, address, &test_val, 1); - s5k83a_read_sensor(sd, address, &ctrl_val, 1); + m5602_read_sensor(sd, address, &old_val, 1); + m5602_write_sensor(sd, address, &test_val, 1); + m5602_read_sensor(sd, address, &ctrl_val, 1); if (ctrl_val == test_val) info("register 0x%x is writeable", address); @@ -231,11 +148,11 @@ void s5k83a_dump_registers(struct sd *sd) info("register 0x%x is read only", address); /* Restore original val */ - s5k83a_write_sensor(sd, address, &old_val, 1); + m5602_write_sensor(sd, address, &old_val, 1); } } info("Read/write register probing complete"); - s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); + m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); } int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) @@ -244,11 +161,15 @@ int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val) u8 data[2]; struct sd *sd = (struct sd *) gspca_dev; - err = s5k83a_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2); + err = m5602_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2); + if (err < 0) + goto out; + data[1] = data[1] << 1; *val = data[1]; - return (err < 0) ? err : 0; +out: + return err; } int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) @@ -259,23 +180,24 @@ int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) data[0] = 0x00; data[1] = 0x20; - err = s5k83a_write_sensor(sd, 0x14, data, 2); + err = m5602_write_sensor(sd, 0x14, data, 2); if (err < 0) - return err; + goto out; data[0] = 0x01; data[1] = 0x00; - err = s5k83a_write_sensor(sd, 0x0d, data, 2); + err = m5602_write_sensor(sd, 0x0d, data, 2); if (err < 0) - return err; + goto out; /* FIXME: This is not sane, we need to figure out the composition of these registers */ data[0] = val >> 3; /* brightness, high 5 bits */ data[1] = val >> 1; /* brightness, high 7 bits */ - err = s5k83a_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2); + err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2); - return (err < 0) ? err : 0; +out: + return err; } int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val) @@ -284,10 +206,14 @@ int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val) u8 data; struct sd *sd = (struct sd *) gspca_dev; - err = s5k83a_read_sensor(sd, S5K83A_WHITENESS, &data, 1); + err = m5602_read_sensor(sd, S5K83A_WHITENESS, &data, 1); + if (err < 0) + goto out; *val = data; - return (err < 0) ? err : 0; + +out: + return err; } int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val) @@ -297,9 +223,9 @@ int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; data[0] = val; - err = s5k83a_write_sensor(sd, S5K83A_WHITENESS, data, 1); + err = m5602_write_sensor(sd, S5K83A_WHITENESS, data, 1); - return (err < 0) ? err : 0; + return err; } int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val) @@ -308,7 +234,9 @@ int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val) u8 data[2]; struct sd *sd = (struct sd *) gspca_dev; - err = s5k83a_read_sensor(sd, S5K83A_GAIN, data, 2); + err = m5602_read_sensor(sd, S5K83A_GAIN, data, 2); + if (err < 0) + goto out; data[1] = data[1] & 0x3f; if (data[1] > S5K83A_MAXIMUM_GAIN) @@ -316,7 +244,8 @@ int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val) *val = data[1]; - return (err < 0) ? err : 0; +out: + return err; } int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) @@ -327,9 +256,8 @@ int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) data[0] = 0; data[1] = val; - err = s5k83a_write_sensor(sd, S5K83A_GAIN, data, 2); - - return (err < 0) ? err : 0; + err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2); + return err; } int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -339,14 +267,15 @@ int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) struct sd *sd = (struct sd *) gspca_dev; data[0] = 0x05; - err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); + err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); if (err < 0) - return err; + goto out; - err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1); + err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1); *val = (data[0] | 0x40) ? 1 : 0; - return (err < 0) ? err : 0; +out: + return err; } int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val) @@ -356,25 +285,26 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; data[0] = 0x05; - err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); + err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); if (err < 0) - return err; + goto out; - err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1); + err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1); if (err < 0) - return err; + goto out; /* set or zero six bit, seven is hflip */ data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK : (data[0] & 0x80) | S5K83A_FLIP_MASK; - err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1); + err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1); if (err < 0) - return err; + goto out; data[0] = (val) ? 0x0b : 0x0a; - err = s5k83a_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1); + err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1); - return (err < 0) ? err : 0; +out: + return err; } int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) @@ -384,14 +314,15 @@ int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) struct sd *sd = (struct sd *) gspca_dev; data[0] = 0x05; - err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); + err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); if (err < 0) - return err; + goto out; - err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1); + err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1); *val = (data[0] | 0x80) ? 1 : 0; - return (err < 0) ? err : 0; +out: + return err; } int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val) @@ -401,23 +332,23 @@ int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val) struct sd *sd = (struct sd *) gspca_dev; data[0] = 0x05; - err = s5k83a_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); + err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); if (err < 0) - return err; + goto out; - err = s5k83a_read_sensor(sd, S5K83A_FLIP, data, 1); + err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1); if (err < 0) - return err; + goto out; /* set or zero seven bit, six is vflip */ data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK : (data[0] & 0x40) | S5K83A_FLIP_MASK; - err = s5k83a_write_sensor(sd, S5K83A_FLIP, data, 1); + err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1); if (err < 0) - return err; + goto out; data[0] = (val) ? 0x0a : 0x0b; - err = s5k83a_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1); - - return (err < 0) ? err : 0; + err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1); +out: + return err; } diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h index ee3ee9cfc..05ccb5b57 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h +++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h @@ -22,15 +22,15 @@ #include "m5602_sensor.h" #define S5K83A_FLIP 0x01 -#define S5K83A_HFLIP_TUNE 0x03 -#define S5K83A_VFLIP_TUNE 0x05 -#define S5K83A_WHITENESS 0x0a +#define S5K83A_HFLIP_TUNE 0x03 +#define S5K83A_VFLIP_TUNE 0x05 +#define S5K83A_WHITENESS 0x0a #define S5K83A_GAIN 0x18 -#define S5K83A_BRIGHTNESS 0x1b -#define S5K83A_PAGE_MAP 0xec +#define S5K83A_BRIGHTNESS 0x1b +#define S5K83A_PAGE_MAP 0xec -#define S5K83A_DEFAULT_BRIGHTNESS 0x71 -#define S5K83A_DEFAULT_WHITENESS 0x7e +#define S5K83A_DEFAULT_BRIGHTNESS 0x71 +#define S5K83A_DEFAULT_WHITENESS 0x7e #define S5K83A_DEFAULT_GAIN 0x00 #define S5K83A_MAXIMUM_GAIN 0x3c #define S5K83A_FLIP_MASK 0x10 @@ -46,13 +46,6 @@ int s5k83a_probe(struct sd *sd); int s5k83a_init(struct sd *sd); int s5k83a_power_down(struct sd *sd); -void s5k83a_dump_registers(struct sd *sd); - -int s5k83a_read_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); -int s5k83a_write_sensor(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val); int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val); @@ -64,15 +57,13 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val); int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val); - static struct m5602_sensor s5k83a = { .name = "S5K83A", .probe = s5k83a_probe, .init = s5k83a_init, .power_down = s5k83a_power_down, - .read_sensor = s5k83a_read_sensor, - .write_sensor = s5k83a_write_sensor, .i2c_slave_id = 0x5a, + .i2c_regW = 2, .nctrls = 5, .ctrls = { { diff --git a/linux/drivers/media/video/gspca/m5602/m5602_sensor.h b/linux/drivers/media/video/gspca/m5602/m5602_sensor.h index 60c9a48e0..261623f0d 100644 --- a/linux/drivers/media/video/gspca/m5602/m5602_sensor.h +++ b/linux/drivers/media/video/gspca/m5602/m5602_sensor.h @@ -49,23 +49,21 @@ struct m5602_sensor { /* What i2c address the sensor is connected to */ u8 i2c_slave_id; + /* Width of each i2c register (in bytes) */ + u8 i2c_regW; + /* Probes if the sensor is connected */ int (*probe)(struct sd *sd); /* Performs a initialization sequence */ int (*init)(struct sd *sd); + /* Executed when the camera starts to send data */ + int (*start)(struct sd *sd); + /* Performs a power down sequence */ int (*power_down)(struct sd *sd); - /* Reads a sensor register */ - int (*read_sensor)(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - - /* Writes to a sensor register */ - int (*write_sensor)(struct sd *sd, const u8 address, - u8 *i2c_data, const u8 len); - int nctrls; struct ctrl ctrls[M5602_MAX_CTRLS]; diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c index 492cdd3b5..3d2090e67 100644 --- a/linux/drivers/media/video/gspca/mars.c +++ b/linux/drivers/media/video/gspca/mars.c @@ -39,7 +39,7 @@ struct sd { static struct ctrl sd_ctrls[] = { }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 589, diff --git a/linux/drivers/media/video/gspca/ov519.c b/linux/drivers/media/video/gspca/ov519.c index b18d98191..5e31a9145 100644 --- a/linux/drivers/media/video/gspca/ov519.c +++ b/linux/drivers/media/video/gspca/ov519.c @@ -3,7 +3,18 @@ * * Copyright (C) 2008 Jean-Francois Moine (http://moinejf.free.fr) * - * (This module is adapted from the ov51x-jpeg package) + * This module is adapted from the ov51x-jpeg package, which itself + * was adapted from the ov511 driver. + * + * Original copyright for the ov511 driver is: + * + * Copyright (c) 1999-2004 Mark W. McClelland + * Support for OV519, OV8610 Copyright (c) 2003 Joerg Heckenbach + * + * ov51x-jpeg original copyright is: + * + * Copyright (c) 2004-2007 Romain Beauxis <toots@rastageeks.org> + * Support for OV7670 sensors was contributed by Sam Skipsey <aoanla@yahoo.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 @@ -153,7 +164,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, @@ -165,7 +176,7 @@ static struct v4l2_pix_format vga_mode[] = { .colorspace = V4L2_COLORSPACE_JPEG, .priv = 0}, }; -static struct v4l2_pix_format sif_mode[] = { +static const struct v4l2_pix_format sif_mode[] = { {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 176, .sizeimage = 176 * 144 * 3 / 8 + 590, diff --git a/linux/drivers/media/video/gspca/ov534.c b/linux/drivers/media/video/gspca/ov534.c index a574be09b..3bf15e401 100644 --- a/linux/drivers/media/video/gspca/ov534.c +++ b/linux/drivers/media/video/gspca/ov534.c @@ -1,6 +1,7 @@ /* * ov534/ov772x gspca driver * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it> + * Copyright (C) 2008 Jim Paris <jim@jtan.com> * * Based on a prototype written by Mark Ferrell <majortrips@gmail.com> * USB protocol reverse engineered by Jim Paris <jim@jtan.com> @@ -42,20 +43,19 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver"); MODULE_LICENSE("GPL"); -/* global parameters */ -static int frame_rate; - /* specific webcam descriptor */ struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - __u8 frame_rate; + __u32 last_fid; + __u32 last_pts; + int frame_rate; }; /* V4L2 controls supported by the driver */ static struct ctrl sd_ctrls[] = { }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, .bytesperline = 640 * 2, .sizeimage = 640 * 480 * 2, @@ -63,80 +63,68 @@ static struct v4l2_pix_format vga_mode[] = { .priv = 0}, }; -static void ov534_reg_write(struct usb_device *udev, u16 reg, u16 val) +static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) { - u16 data = val; + struct usb_device *udev = gspca_dev->dev; int ret; - PDEBUG(D_USBO, "reg=0x%04x, val=0%04x", reg, val); + PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val); + gspca_dev->usb_buf[0] = val; ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x1, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0, reg, &data, 1, CTRL_TIMEOUT); + 0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); if (ret < 0) PDEBUG(D_ERR, "write failed"); } -static u16 ov534_reg_read(struct usb_device *udev, u16 reg) +static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) { - u16 data; + struct usb_device *udev = gspca_dev->dev; int ret; ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x1, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0x0, reg, &data, 1, CTRL_TIMEOUT); - PDEBUG(D_USBI, "reg=0x%04x, data=0x%04x", reg, data); + 0x0, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); + PDEBUG(D_USBI, "reg=0x%04x, data=0x%02x", reg, gspca_dev->usb_buf[0]); if (ret < 0) PDEBUG(D_ERR, "read failed"); - return data; -} - -static void ov534_reg_verify_write(struct usb_device *udev, u16 reg, u16 val) -{ - u16 data; - - ov534_reg_write(udev, reg, val); - data = ov534_reg_read(udev, reg); - if (data != val) { - PDEBUG(D_ERR | D_USBO, - "unexpected result from read: 0x%04x != 0x%04x", val, - data); - } + return gspca_dev->usb_buf[0]; } /* Two bits control LED: 0x21 bit 7 and 0x23 bit 7. * (direction and output)? */ -static void ov534_set_led(struct usb_device *udev, int status) +static void ov534_set_led(struct gspca_dev *gspca_dev, int status) { - u16 data; + u8 data; PDEBUG(D_CONF, "led status: %d", status); - data = ov534_reg_read(udev, 0x21); + data = ov534_reg_read(gspca_dev, 0x21); data |= 0x80; - ov534_reg_write(udev, 0x21, data); + ov534_reg_write(gspca_dev, 0x21, data); - data = ov534_reg_read(udev, 0x23); + data = ov534_reg_read(gspca_dev, 0x23); if (status) data |= 0x80; else data &= ~(0x80); - ov534_reg_write(udev, 0x23, data); + ov534_reg_write(gspca_dev, 0x23, data); } -static int sccb_check_status(struct usb_device *udev) +static int sccb_check_status(struct gspca_dev *gspca_dev) { - u16 data; + u8 data; int i; for (i = 0; i < 5; i++) { - data = ov534_reg_read(udev, OV534_REG_STATUS); + data = ov534_reg_read(gspca_dev, OV534_REG_STATUS); - switch (data & 0xFF) { + switch (data) { case 0x00: return 1; case 0x04: @@ -144,195 +132,243 @@ static int sccb_check_status(struct usb_device *udev) case 0x03: break; default: - PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5\n", + PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5", data, i + 1); } } return 0; } -static void sccb_reg_write(struct usb_device *udev, u16 reg, u16 val) +static void sccb_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) { - PDEBUG(D_USBO, "reg: 0x%04x, val: 0x%04x", reg, val); - ov534_reg_write(udev, OV534_REG_SUBADDR, reg); - ov534_reg_write(udev, OV534_REG_WRITE, val); - ov534_reg_write(udev, OV534_REG_OPERATION, OV534_OP_WRITE_3); + PDEBUG(D_USBO, "reg: 0x%04x, val: 0x%02x", reg, val); + ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); + ov534_reg_write(gspca_dev, OV534_REG_WRITE, val); + ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); - if (!sccb_check_status(udev)) + if (!sccb_check_status(gspca_dev)) PDEBUG(D_ERR, "sccb_reg_write failed"); } +#ifdef GSPCA_DEBUG +static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg) +{ + ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); + ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); + if (!sccb_check_status(gspca_dev)) + PDEBUG(D_ERR, "sccb_reg_read failed 1"); + + ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); + if (!sccb_check_status(gspca_dev)) + PDEBUG(D_ERR, "sccb_reg_read failed 2"); + + return ov534_reg_read(gspca_dev, OV534_REG_READ); +} +#endif + +static const __u8 ov534_reg_initdata[][2] = { + { 0xe7, 0x3a }, + + { OV534_REG_ADDRESS, 0x42 }, /* select OV772x sensor */ + + { 0xc2, 0x0c }, + { 0x88, 0xf8 }, + { 0xc3, 0x69 }, + { 0x89, 0xff }, + { 0x76, 0x03 }, + { 0x92, 0x01 }, + { 0x93, 0x18 }, + { 0x94, 0x10 }, + { 0x95, 0x10 }, + { 0xe2, 0x00 }, + { 0xe7, 0x3e }, + + { 0x96, 0x00 }, + + { 0x97, 0x20 }, + { 0x97, 0x20 }, + { 0x97, 0x20 }, + { 0x97, 0x0a }, + { 0x97, 0x3f }, + { 0x97, 0x4a }, + { 0x97, 0x20 }, + { 0x97, 0x15 }, + { 0x97, 0x0b }, + + { 0x8e, 0x40 }, + { 0x1f, 0x81 }, + { 0x34, 0x05 }, + { 0xe3, 0x04 }, + { 0x88, 0x00 }, + { 0x89, 0x00 }, + { 0x76, 0x00 }, + { 0xe7, 0x2e }, + { 0x31, 0xf9 }, + { 0x25, 0x42 }, + { 0x21, 0xf0 }, + + { 0x1c, 0x00 }, + { 0x1d, 0x40 }, + { 0x1d, 0x02 }, /* payload size 0x0200 * 4 = 2048 bytes */ + { 0x1d, 0x00 }, /* payload size */ + { 0x1d, 0x02 }, /* frame size 0x025800 * 4 = 614400 */ + { 0x1d, 0x58 }, /* frame size */ + { 0x1d, 0x00 }, /* frame size */ + + { 0x1c, 0x0a }, + { 0x1d, 0x08 }, /* turn on UVC header */ + { 0x1d, 0x0e }, /* .. */ + + { 0x8d, 0x1c }, + { 0x8e, 0x80 }, + { 0xe5, 0x04 }, + + { 0xc0, 0x50 }, + { 0xc1, 0x3c }, + { 0xc2, 0x0c }, +}; + +static const __u8 ov772x_reg_initdata[][2] = { + { 0x12, 0x80 }, + { 0x11, 0x01 }, + + { 0x3d, 0x03 }, + { 0x17, 0x26 }, + { 0x18, 0xa0 }, + { 0x19, 0x07 }, + { 0x1a, 0xf0 }, + { 0x32, 0x00 }, + { 0x29, 0xa0 }, + { 0x2c, 0xf0 }, + { 0x65, 0x20 }, + { 0x11, 0x01 }, + { 0x42, 0x7f }, + { 0x63, 0xe0 }, + { 0x64, 0xff }, + { 0x66, 0x00 }, + { 0x13, 0xf0 }, + { 0x0d, 0x41 }, + { 0x0f, 0xc5 }, + { 0x14, 0x11 }, + + { 0x22, 0x7f }, + { 0x23, 0x03 }, + { 0x24, 0x40 }, + { 0x25, 0x30 }, + { 0x26, 0xa1 }, + { 0x2a, 0x00 }, + { 0x2b, 0x00 }, + { 0x6b, 0xaa }, + { 0x13, 0xff }, + + { 0x90, 0x05 }, + { 0x91, 0x01 }, + { 0x92, 0x03 }, + { 0x93, 0x00 }, + { 0x94, 0x60 }, + { 0x95, 0x3c }, + { 0x96, 0x24 }, + { 0x97, 0x1e }, + { 0x98, 0x62 }, + { 0x99, 0x80 }, + { 0x9a, 0x1e }, + { 0x9b, 0x08 }, + { 0x9c, 0x20 }, + { 0x9e, 0x81 }, + + { 0xa6, 0x04 }, + { 0x7e, 0x0c }, + { 0x7f, 0x16 }, + { 0x80, 0x2a }, + { 0x81, 0x4e }, + { 0x82, 0x61 }, + { 0x83, 0x6f }, + { 0x84, 0x7b }, + { 0x85, 0x86 }, + { 0x86, 0x8e }, + { 0x87, 0x97 }, + { 0x88, 0xa4 }, + { 0x89, 0xaf }, + { 0x8a, 0xc5 }, + { 0x8b, 0xd7 }, + { 0x8c, 0xe8 }, + { 0x8d, 0x20 }, + + { 0x0c, 0x90 }, + + { 0x2b, 0x00 }, + { 0x22, 0x7f }, + { 0x23, 0x03 }, + { 0x11, 0x01 }, + { 0x0c, 0xd0 }, + { 0x64, 0xff }, + { 0x0d, 0x41 }, + + { 0x14, 0x41 }, + { 0x0e, 0xcd }, + { 0xac, 0xbf }, + { 0x8e, 0x00 }, + { 0x0c, 0xd0 } +}; + +/* set framerate */ +static void ov534_set_frame_rate(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int fr = sd->frame_rate; + + switch (fr) { + case 50: + sccb_reg_write(gspca_dev, 0x11, 0x01); + sccb_reg_write(gspca_dev, 0x0d, 0x41); + ov534_reg_write(gspca_dev, 0xe5, 0x02); + break; + case 40: + sccb_reg_write(gspca_dev, 0x11, 0x02); + sccb_reg_write(gspca_dev, 0x0d, 0xc1); + ov534_reg_write(gspca_dev, 0xe5, 0x04); + break; +/* case 30: */ + default: + fr = 30; + sccb_reg_write(gspca_dev, 0x11, 0x04); + sccb_reg_write(gspca_dev, 0x0d, 0x81); + ov534_reg_write(gspca_dev, 0xe5, 0x02); + break; + case 15: + sccb_reg_write(gspca_dev, 0x11, 0x03); + sccb_reg_write(gspca_dev, 0x0d, 0x41); + ov534_reg_write(gspca_dev, 0xe5, 0x04); + break; + } + + sd->frame_rate = fr; + PDEBUG(D_PROBE, "frame_rate: %d", fr); +} + /* setup method */ -static void ov534_setup(struct usb_device *udev) +static void ov534_setup(struct gspca_dev *gspca_dev) { - ov534_reg_verify_write(udev, 0xe7, 0x3a); - - ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60); - ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60); - ov534_reg_write(udev, OV534_REG_ADDRESS, 0x60); - ov534_reg_write(udev, OV534_REG_ADDRESS, 0x42); - - ov534_reg_verify_write(udev, 0xc2, 0x0c); - ov534_reg_verify_write(udev, 0x88, 0xf8); - ov534_reg_verify_write(udev, 0xc3, 0x69); - ov534_reg_verify_write(udev, 0x89, 0xff); - ov534_reg_verify_write(udev, 0x76, 0x03); - ov534_reg_verify_write(udev, 0x92, 0x01); - ov534_reg_verify_write(udev, 0x93, 0x18); - ov534_reg_verify_write(udev, 0x94, 0x10); - ov534_reg_verify_write(udev, 0x95, 0x10); - ov534_reg_verify_write(udev, 0xe2, 0x00); - ov534_reg_verify_write(udev, 0xe7, 0x3e); - - ov534_reg_write(udev, 0x1c, 0x0a); - ov534_reg_write(udev, 0x1d, 0x22); - ov534_reg_write(udev, 0x1d, 0x06); - - ov534_reg_verify_write(udev, 0x96, 0x00); - - ov534_reg_write(udev, 0x97, 0x20); - ov534_reg_write(udev, 0x97, 0x20); - ov534_reg_write(udev, 0x97, 0x20); - ov534_reg_write(udev, 0x97, 0x0a); - ov534_reg_write(udev, 0x97, 0x3f); - ov534_reg_write(udev, 0x97, 0x4a); - ov534_reg_write(udev, 0x97, 0x20); - ov534_reg_write(udev, 0x97, 0x15); - ov534_reg_write(udev, 0x97, 0x0b); - - ov534_reg_verify_write(udev, 0x8e, 0x40); - ov534_reg_verify_write(udev, 0x1f, 0x81); - ov534_reg_verify_write(udev, 0x34, 0x05); - ov534_reg_verify_write(udev, 0xe3, 0x04); - ov534_reg_verify_write(udev, 0x88, 0x00); - ov534_reg_verify_write(udev, 0x89, 0x00); - ov534_reg_verify_write(udev, 0x76, 0x00); - ov534_reg_verify_write(udev, 0xe7, 0x2e); - ov534_reg_verify_write(udev, 0x31, 0xf9); - ov534_reg_verify_write(udev, 0x25, 0x42); - ov534_reg_verify_write(udev, 0x21, 0xf0); - - ov534_reg_write(udev, 0x1c, 0x00); - ov534_reg_write(udev, 0x1d, 0x40); - ov534_reg_write(udev, 0x1d, 0x02); - ov534_reg_write(udev, 0x1d, 0x00); - ov534_reg_write(udev, 0x1d, 0x02); - ov534_reg_write(udev, 0x1d, 0x57); - ov534_reg_write(udev, 0x1d, 0xff); - - ov534_reg_verify_write(udev, 0x8d, 0x1c); - ov534_reg_verify_write(udev, 0x8e, 0x80); - ov534_reg_verify_write(udev, 0xe5, 0x04); - - ov534_set_led(udev, 1); - - sccb_reg_write(udev, 0x12, 0x80); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x11, 0x01); - - ov534_set_led(udev, 0); - - sccb_reg_write(udev, 0x3d, 0x03); - sccb_reg_write(udev, 0x17, 0x26); - sccb_reg_write(udev, 0x18, 0xa0); - sccb_reg_write(udev, 0x19, 0x07); - sccb_reg_write(udev, 0x1a, 0xf0); - sccb_reg_write(udev, 0x32, 0x00); - sccb_reg_write(udev, 0x29, 0xa0); - sccb_reg_write(udev, 0x2c, 0xf0); - sccb_reg_write(udev, 0x65, 0x20); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x42, 0x7f); - sccb_reg_write(udev, 0x63, 0xe0); - sccb_reg_write(udev, 0x64, 0xff); - sccb_reg_write(udev, 0x66, 0x00); - sccb_reg_write(udev, 0x13, 0xf0); - sccb_reg_write(udev, 0x0d, 0x41); - sccb_reg_write(udev, 0x0f, 0xc5); - sccb_reg_write(udev, 0x14, 0x11); - - ov534_set_led(udev, 1); - - sccb_reg_write(udev, 0x22, 0x7f); - sccb_reg_write(udev, 0x23, 0x03); - sccb_reg_write(udev, 0x24, 0x40); - sccb_reg_write(udev, 0x25, 0x30); - sccb_reg_write(udev, 0x26, 0xa1); - sccb_reg_write(udev, 0x2a, 0x00); - sccb_reg_write(udev, 0x2b, 0x00); - sccb_reg_write(udev, 0x6b, 0xaa); - sccb_reg_write(udev, 0x13, 0xff); - - ov534_set_led(udev, 0); - - sccb_reg_write(udev, 0x90, 0x05); - sccb_reg_write(udev, 0x91, 0x01); - sccb_reg_write(udev, 0x92, 0x03); - sccb_reg_write(udev, 0x93, 0x00); - sccb_reg_write(udev, 0x94, 0x60); - sccb_reg_write(udev, 0x95, 0x3c); - sccb_reg_write(udev, 0x96, 0x24); - sccb_reg_write(udev, 0x97, 0x1e); - sccb_reg_write(udev, 0x98, 0x62); - sccb_reg_write(udev, 0x99, 0x80); - sccb_reg_write(udev, 0x9a, 0x1e); - sccb_reg_write(udev, 0x9b, 0x08); - sccb_reg_write(udev, 0x9c, 0x20); - sccb_reg_write(udev, 0x9e, 0x81); - - ov534_set_led(udev, 1); - - sccb_reg_write(udev, 0xa6, 0x04); - sccb_reg_write(udev, 0x7e, 0x0c); - sccb_reg_write(udev, 0x7f, 0x16); - sccb_reg_write(udev, 0x80, 0x2a); - sccb_reg_write(udev, 0x81, 0x4e); - sccb_reg_write(udev, 0x82, 0x61); - sccb_reg_write(udev, 0x83, 0x6f); - sccb_reg_write(udev, 0x84, 0x7b); - sccb_reg_write(udev, 0x85, 0x86); - sccb_reg_write(udev, 0x86, 0x8e); - sccb_reg_write(udev, 0x87, 0x97); - sccb_reg_write(udev, 0x88, 0xa4); - sccb_reg_write(udev, 0x89, 0xaf); - sccb_reg_write(udev, 0x8a, 0xc5); - sccb_reg_write(udev, 0x8b, 0xd7); - sccb_reg_write(udev, 0x8c, 0xe8); - sccb_reg_write(udev, 0x8d, 0x20); - - sccb_reg_write(udev, 0x0c, 0x90); - - ov534_reg_verify_write(udev, 0xc0, 0x50); - ov534_reg_verify_write(udev, 0xc1, 0x3c); - ov534_reg_verify_write(udev, 0xc2, 0x0c); - - ov534_set_led(udev, 1); - - sccb_reg_write(udev, 0x2b, 0x00); - sccb_reg_write(udev, 0x22, 0x7f); - sccb_reg_write(udev, 0x23, 0x03); - sccb_reg_write(udev, 0x11, 0x01); - sccb_reg_write(udev, 0x0c, 0xd0); - sccb_reg_write(udev, 0x64, 0xff); - sccb_reg_write(udev, 0x0d, 0x41); - - sccb_reg_write(udev, 0x14, 0x41); - sccb_reg_write(udev, 0x0e, 0xcd); - sccb_reg_write(udev, 0xac, 0xbf); - sccb_reg_write(udev, 0x8e, 0x00); - sccb_reg_write(udev, 0x0c, 0xd0); - - ov534_reg_write(udev, 0xe0, 0x09); - ov534_set_led(udev, 0); + int i; + + /* Initialize bridge chip */ + for (i = 0; i < ARRAY_SIZE(ov534_reg_initdata); i++) + ov534_reg_write(gspca_dev, ov534_reg_initdata[i][0], + ov534_reg_initdata[i][1]); + + PDEBUG(D_PROBE, "sensor is ov%02x%02x", + sccb_reg_read(gspca_dev, 0x0a), + sccb_reg_read(gspca_dev, 0x0b)); + + ov534_set_led(gspca_dev, 1); + + /* Initialize sensor */ + for (i = 0; i < ARRAY_SIZE(ov772x_reg_initdata); i++) + sccb_reg_write(gspca_dev, ov772x_reg_initdata[i][0], + ov772x_reg_initdata[i][1]); + + ov534_reg_write(gspca_dev, 0xe0, 0x09); + ov534_set_led(gspca_dev, 0); } /* this function is called at probe time */ @@ -347,70 +383,26 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = vga_mode; cam->nmodes = ARRAY_SIZE(vga_mode); - cam->bulk_size = vga_mode[0].sizeimage; + cam->bulk_size = 16384; cam->bulk_nurbs = 2; - PDEBUG(D_PROBE, "bulk_size = %d", cam->bulk_size); - 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; - ov534_setup(gspca_dev->dev); - - if (frame_rate > 0) - sd->frame_rate = frame_rate; - - PDEBUG(D_PROBE, "frame_rate = %d", sd->frame_rate); - - switch (sd->frame_rate) { - case 50: - sccb_reg_write(gspca_dev->dev, 0x11, 0x01); - sccb_check_status(gspca_dev->dev); - sccb_reg_write(gspca_dev->dev, 0x0d, 0x41); - sccb_check_status(gspca_dev->dev); - ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x02); - break; - case 40: - sccb_reg_write(gspca_dev->dev, 0x11, 0x02); - sccb_check_status(gspca_dev->dev); - sccb_reg_write(gspca_dev->dev, 0x0d, 0xc1); - sccb_check_status(gspca_dev->dev); - ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x04); - break; - case 30: - default: - sccb_reg_write(gspca_dev->dev, 0x11, 0x04); - sccb_check_status(gspca_dev->dev); - sccb_reg_write(gspca_dev->dev, 0x0d, 0x81); - sccb_check_status(gspca_dev->dev); - ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x02); - break; - case 15: - sccb_reg_write(gspca_dev->dev, 0x11, 0x03); - sccb_check_status(gspca_dev->dev); - sccb_reg_write(gspca_dev->dev, 0x0d, 0x41); - sccb_check_status(gspca_dev->dev); - ov534_reg_verify_write(gspca_dev->dev, 0xe5, 0x04); - break; - }; + ov534_setup(gspca_dev); + ov534_set_frame_rate(gspca_dev); return 0; } static int sd_start(struct gspca_dev *gspca_dev) { - PDEBUG(D_PROBE, "width = %d, height = %d", - gspca_dev->width, gspca_dev->height); - - gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height * 2; - /* start streaming data */ - ov534_set_led(gspca_dev->dev, 1); - ov534_reg_write(gspca_dev->dev, 0xe0, 0x00); + ov534_set_led(gspca_dev, 1); + ov534_reg_write(gspca_dev, 0xe0, 0x00); return 0; } @@ -418,29 +410,134 @@ static int sd_start(struct gspca_dev *gspca_dev) static void sd_stopN(struct gspca_dev *gspca_dev) { /* stop streaming data */ - ov534_reg_write(gspca_dev->dev, 0xe0, 0x09); - ov534_set_led(gspca_dev->dev, 0); + ov534_reg_write(gspca_dev, 0xe0, 0x09); + ov534_set_led(gspca_dev, 0); } +/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ +#define UVC_STREAM_EOH (1 << 7) +#define UVC_STREAM_ERR (1 << 6) +#define UVC_STREAM_STI (1 << 5) +#define UVC_STREAM_RES (1 << 4) +#define UVC_STREAM_SCR (1 << 3) +#define UVC_STREAM_PTS (1 << 2) +#define UVC_STREAM_EOF (1 << 1) +#define UVC_STREAM_FID (1 << 0) + static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame, __u8 *data, int len) { - /* - * The current camera setup doesn't stream the last pixel, so we set it - * to a dummy value - */ - __u8 last_pixel[4] = { 0, 0, 0, 0 }; - int framesize = gspca_dev->cam.bulk_size; - - if (len == framesize - 4) { - frame = - gspca_frame_add(gspca_dev, FIRST_PACKET, frame, data, len); - frame = - gspca_frame_add(gspca_dev, LAST_PACKET, frame, last_pixel, - 4); - } else - PDEBUG(D_PACK, "packet len = %d, framesize = %d", len, - framesize); + struct sd *sd = (struct sd *) gspca_dev; + __u32 this_pts; + int this_fid; + int remaining_len = len; + __u8 *next_data = data; + +scan_next: + if (remaining_len <= 0) + return; + + data = next_data; + len = min(remaining_len, 2048); + remaining_len -= len; + next_data += len; + + /* Payloads are prefixed with a UVC-style header. We + consider a frame to start when the FID toggles, or the PTS + changes. A frame ends when EOF is set, and we've received + the correct number of bytes. */ + + /* Verify UVC header. Header length is always 12 */ + if (data[0] != 12 || len < 12) { + PDEBUG(D_PACK, "bad header"); + goto discard; + } + + /* Check errors */ + if (data[1] & UVC_STREAM_ERR) { + PDEBUG(D_PACK, "payload error"); + goto discard; + } + + /* Extract PTS and FID */ + if (!(data[1] & UVC_STREAM_PTS)) { + PDEBUG(D_PACK, "PTS not present"); + goto discard; + } + this_pts = (data[5] << 24) | (data[4] << 16) | (data[3] << 8) | data[2]; + this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0; + + /* If PTS or FID has changed, start a new frame. */ + if (this_pts != sd->last_pts || this_fid != sd->last_fid) { + gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0); + sd->last_pts = this_pts; + sd->last_fid = this_fid; + } + + /* Add the data from this payload */ + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data + 12, len - 12); + + /* If this packet is marked as EOF, end the frame */ + if (data[1] & UVC_STREAM_EOF) { + sd->last_pts = 0; + + if ((frame->data_end - frame->data) != + (gspca_dev->width * gspca_dev->height * 2)) { + PDEBUG(D_PACK, "short frame"); + goto discard; + } + + gspca_frame_add(gspca_dev, LAST_PACKET, frame, NULL, 0); + } + + /* Done this payload */ + goto scan_next; + +discard: + /* Discard data until a new frame starts. */ + gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0); + goto scan_next; +} + +/* get stream parameters (framerate) */ +static int sd_get_streamparm(struct gspca_dev *gspca_dev, + struct v4l2_streamparm *parm) +{ + struct v4l2_captureparm *cp = &parm->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + struct sd *sd = (struct sd *) gspca_dev; + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + cp->capability |= V4L2_CAP_TIMEPERFRAME; + tpf->numerator = 1; + tpf->denominator = sd->frame_rate; + + return 0; +} + +/* set stream parameters (framerate) */ +static int sd_set_streamparm(struct gspca_dev *gspca_dev, + struct v4l2_streamparm *parm) +{ + struct v4l2_captureparm *cp = &parm->parm.capture; + struct v4l2_fract *tpf = &cp->timeperframe; + struct sd *sd = (struct sd *) gspca_dev; + + if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + /* Set requested framerate */ + sd->frame_rate = tpf->denominator / tpf->numerator; + ov534_set_frame_rate(gspca_dev); + + /* Return the actual framerate */ + tpf->numerator = 1; + tpf->denominator = sd->frame_rate; + + return 0; } /* sub-driver description */ @@ -453,6 +550,8 @@ static const struct sd_desc sd_desc = { .start = sd_start, .stopN = sd_stopN, .pkt_scan = sd_pkt_scan, + .get_streamparm = sd_get_streamparm, + .set_streamparm = sd_set_streamparm, }; /* -- module initialisation -- */ @@ -500,6 +599,3 @@ static void __exit sd_mod_exit(void) module_init(sd_mod_init); module_exit(sd_mod_exit); - -module_param(frame_rate, int, 0644); -MODULE_PARM_DESC(frame_rate, "Frame rate (15, 30, 40, 50)"); diff --git a/linux/drivers/media/video/gspca/pac207.c b/linux/drivers/media/video/gspca/pac207.c index 39473e6b9..c90ac852b 100644 --- a/linux/drivers/media/video/gspca/pac207.c +++ b/linux/drivers/media/video/gspca/pac207.c @@ -1,7 +1,7 @@ /* * Pixart PAC207BCA library * - * Copyright (C) 2008 Hans de Goede <j.w.r.degoede@hhs.nl> + * Copyright (C) 2008 Hans de Goede <hdgoede@redhat.com> * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr * @@ -27,7 +27,7 @@ #include "gspca.h" -MODULE_AUTHOR("Hans de Goede <j.w.r.degoede@hhs.nl>"); +MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>"); MODULE_DESCRIPTION("Pixart PAC207"); MODULE_LICENSE("GPL"); @@ -149,7 +149,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format sif_mode[] = { +static const struct v4l2_pix_format sif_mode[] = { {176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE, .bytesperline = 176, .sizeimage = (176 + 2) * 144, @@ -529,6 +529,7 @@ static const struct sd_desc sd_desc = { static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x041e, 0x4028)}, {USB_DEVICE(0x093a, 0x2460)}, + {USB_DEVICE(0x093a, 0x2461)}, {USB_DEVICE(0x093a, 0x2463)}, {USB_DEVICE(0x093a, 0x2464)}, {USB_DEVICE(0x093a, 0x2468)}, diff --git a/linux/drivers/media/video/gspca/pac7311.c b/linux/drivers/media/video/gspca/pac7311.c index f443df77e..83ab0df0e 100644 --- a/linux/drivers/media/video/gspca/pac7311.c +++ b/linux/drivers/media/video/gspca/pac7311.c @@ -226,7 +226,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120 * 3 / 8 + 590, @@ -1078,10 +1078,13 @@ static __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x093a, 0x2608), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311}, {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311}, + {USB_DEVICE(0x093a, 0x2620), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302}, + {USB_DEVICE(0x093a, 0x2622), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x2626), .driver_info = SENSOR_PAC7302}, {USB_DEVICE(0x093a, 0x262a), .driver_info = SENSOR_PAC7302}, + {USB_DEVICE(0x093a, 0x262c), .driver_info = SENSOR_PAC7302}, {} }; MODULE_DEVICE_TABLE(usb, device_table); diff --git a/linux/drivers/media/video/gspca/sonixb.c b/linux/drivers/media/video/gspca/sonixb.c index 5ca8ab780..75b44b362 100644 --- a/linux/drivers/media/video/gspca/sonixb.c +++ b/linux/drivers/media/video/gspca/sonixb.c @@ -227,7 +227,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120, @@ -249,7 +249,7 @@ static struct v4l2_pix_format vga_mode[] = { .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; -static struct v4l2_pix_format sif_mode[] = { +static const struct v4l2_pix_format sif_mode[] = { {160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120, diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c index 182b84f1c..217db0d88 100644 --- a/linux/drivers/media/video/gspca/sonixj.c +++ b/linux/drivers/media/video/gspca/sonixj.c @@ -37,24 +37,26 @@ struct sd { atomic_t avg_lum; unsigned int exposure; - unsigned short brightness; - unsigned char contrast; - unsigned char colors; - unsigned char autogain; + __u16 brightness; + __u8 contrast; + __u8 colors; + __u8 autogain; + __u8 blue; + __u8 red; __u8 vflip; /* ov7630 only */ __u8 infrared; /* mi0360 only */ - signed char ag_cnt; + __s8 ag_cnt; #define AG_CNT_START 13 - char qindex; - unsigned char bridge; + __u8 qindex; + __u8 bridge; #define BRIDGE_SN9C102P 0 #define BRIDGE_SN9C105 1 #define BRIDGE_SN9C110 2 #define BRIDGE_SN9C120 3 #define BRIDGE_SN9C325 4 - char sensor; /* Type of image sensor chip */ + __u8 sensor; /* Type of image sensor chip */ #define SENSOR_HV7131R 0 #define SENSOR_MI0360 1 #define SENSOR_MO4000 2 @@ -62,7 +64,7 @@ struct sd { #define SENSOR_OV7630 4 #define SENSOR_OV7648 5 #define SENSOR_OV7660 6 - unsigned char i2c_base; + __u8 i2c_base; }; /* V4L2 controls supported by the driver */ @@ -72,6 +74,10 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val); static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getred_balance(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_setvflip(struct gspca_dev *gspca_dev, __s32 val); @@ -89,7 +95,7 @@ static struct ctrl sd_ctrls[] = { #define BRIGHTNESS_MAX 0xffff .maximum = BRIGHTNESS_MAX, .step = 1, -#define BRIGHTNESS_DEF 0x7fff +#define BRIGHTNESS_DEF 0x8000 .default_value = BRIGHTNESS_DEF, }, .set = sd_setbrightness, @@ -116,7 +122,7 @@ static struct ctrl sd_ctrls[] = { .type = V4L2_CTRL_TYPE_INTEGER, .name = "Color", .minimum = 0, - .maximum = 64, + .maximum = 40, .step = 1, #define COLOR_DEF 32 .default_value = COLOR_DEF, @@ -124,7 +130,35 @@ static struct ctrl sd_ctrls[] = { .set = sd_setcolors, .get = sd_getcolors, }, -#define AUTOGAIN_IDX 3 + { + { + .id = V4L2_CID_BLUE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Blue Balance", + .minimum = 24, + .maximum = 40, + .step = 1, +#define BLUE_BALANCE_DEF 32 + .default_value = BLUE_BALANCE_DEF, + }, + .set = sd_setblue_balance, + .get = sd_getblue_balance, + }, + { + { + .id = V4L2_CID_RED_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Red Balance", + .minimum = 24, + .maximum = 40, + .step = 1, +#define RED_BALANCE_DEF 32 + .default_value = RED_BALANCE_DEF, + }, + .set = sd_setred_balance, + .get = sd_getred_balance, + }, +#define AUTOGAIN_IDX 5 { { .id = V4L2_CID_AUTOGAIN, @@ -140,7 +174,7 @@ static struct ctrl sd_ctrls[] = { .get = sd_getautogain, }, /* ov7630 only */ -#define VFLIP_IDX 4 +#define VFLIP_IDX 6 { { .id = V4L2_CID_VFLIP, @@ -156,7 +190,7 @@ static struct ctrl sd_ctrls[] = { .get = sd_getvflip, }, /* mi0360 only */ -#define INFRARED_IDX 5 +#define INFRARED_IDX 7 { { .id = V4L2_CID_INFRARED, @@ -173,7 +207,25 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +/* table of the disabled controls */ +static __u32 ctrl_dis[] = { + (1 << INFRARED_IDX) | (1 << VFLIP_IDX), + /* SENSOR_HV7131R 0 */ + (1 << VFLIP_IDX), + /* SENSOR_MI0360 1 */ + (1 << INFRARED_IDX) | (1 << VFLIP_IDX), + /* SENSOR_MO4000 2 */ + (1 << INFRARED_IDX) | (1 << VFLIP_IDX), + /* SENSOR_OM6802 3 */ + (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX), + /* SENSOR_OV7630 4 */ + (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX), + /* SENSOR_OV7648 5 */ + (1 << AUTOGAIN_IDX) | (1 << INFRARED_IDX) | (1 << VFLIP_IDX), + /* SENSOR_OV7660 6 */ +}; + +static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120 * 4 / 8 + 590, @@ -767,8 +819,6 @@ static void i2c_r5(struct gspca_dev *gspca_dev, __u8 reg) static int probesensor(struct gspca_dev *gspca_dev) { - struct sd *sd = (struct sd *) gspca_dev; - i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */ msleep(10); reg_w1(gspca_dev, 0x02, 0x66); /* Gpio on */ @@ -780,8 +830,7 @@ static int probesensor(struct gspca_dev *gspca_dev) && gspca_dev->usb_buf[3] == 0x00 && gspca_dev->usb_buf[4] == 0x00) { PDEBUG(D_PROBE, "Find Sensor sn9c102P HV7131R"); - sd->sensor = SENSOR_HV7131R; - return SENSOR_HV7131R; + return 0; } PDEBUG(D_PROBE, "Find Sensor 0x%02x 0x%02x 0x%02x", gspca_dev->usb_buf[0], gspca_dev->usb_buf[1], @@ -989,22 +1038,14 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->brightness = BRIGHTNESS_DEF; sd->contrast = CONTRAST_DEF; sd->colors = COLOR_DEF; + sd->blue = BLUE_BALANCE_DEF; + sd->red = RED_BALANCE_DEF; sd->autogain = AUTOGAIN_DEF; sd->ag_cnt = -1; sd->vflip = VFLIP_DEF; sd->infrared = INFRARED_DEF; - switch (sd->sensor) { - case SENSOR_OV7630: - case SENSOR_OV7648: - case SENSOR_OV7660: - gspca_dev->ctrl_dis = (1 << AUTOGAIN_IDX); - break; - } - if (sd->sensor != SENSOR_OV7630) - gspca_dev->ctrl_dis |= (1 << VFLIP_IDX); - if (sd->sensor != SENSOR_MI0360) - gspca_dev->ctrl_dis |= (1 << INFRARED_IDX); + gspca_dev->ctrl_dis = ctrl_dis[sd->sensor]; return 0; } @@ -1012,7 +1053,6 @@ static int sd_config(struct gspca_dev *gspca_dev, static int sd_init(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; -/* const __u8 *sn9c1xx; */ __u8 regGpio[] = { 0x29, 0x74 }; __u8 regF1; @@ -1051,12 +1091,7 @@ static int sd_init(struct gspca_dev *gspca_dev) reg_w1(gspca_dev, 0xf1, 0x01); -#if 1 /*jfm: from win trace*/ return 0; -#else - sn9c1xx = sn_tb[(int) sd->sensor]; - return configure_gpio(gspca_dev, sn9c1xx); -#endif } static unsigned int setexposure(struct gspca_dev *gspca_dev, @@ -1136,32 +1171,13 @@ static unsigned int setexposure(struct gspca_dev *gspca_dev, return expo; } -/* this function is used for sensors o76xx only */ -static void setbrightcont(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - int val; - __u8 reg84_full[0x15]; - - memcpy(reg84_full, reg84, sizeof reg84_full); - val = sd->contrast * 0x30 / CONTRAST_MAX + 0x10; /* 10..40 */ - reg84_full[0] = (val + 1) / 2; /* red */ - reg84_full[2] = val; /* green */ - reg84_full[4] = (val + 1) / 5; /* blue */ - val = (sd->brightness - BRIGHTNESS_DEF) * 0x10 - / BRIGHTNESS_MAX; - reg84_full[0x12] = val & 0x1f; /* 5:0 signed value */ - reg_w(gspca_dev, 0x84, reg84_full, sizeof reg84_full); -} - -/* sensor != ov76xx */ static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; unsigned int expo; __u8 k2; - k2 = sd->brightness >> 10; + k2 = ((int) sd->brightness - 0x8000) >> 10; switch (sd->sensor) { case SENSOR_HV7131R: expo = sd->brightness << 4; @@ -1183,38 +1199,49 @@ static void setbrightness(struct gspca_dev *gspca_dev) break; } - reg_w1(gspca_dev, 0x96, k2); + reg_w1(gspca_dev, 0x96, k2); /* color matrix Y offset */ } -/* sensor != ov76xx */ static void setcontrast(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u8 k2; - __u8 contrast[] = { 0x00, 0x00, 0x28, 0x00, 0x07, 0x00 }; - - k2 = sd->contrast; - contrast[2] = k2; - contrast[0] = (k2 + 1) >> 1; - contrast[4] = (k2 + 1) / 5; - reg_w(gspca_dev, 0x84, contrast, 6); + __u8 contrast[6]; + + k2 = sd->contrast * 0x30 / (CONTRAST_MAX + 1) + 0x10; /* 10..40 */ + contrast[0] = (k2 + 1) / 2; /* red */ + contrast[1] = 0; + contrast[2] = k2; /* green */ + contrast[3] = 0; + contrast[4] = (k2 + 1) / 5; /* blue */ + contrast[5] = 0; + reg_w(gspca_dev, 0x84, contrast, sizeof contrast); } static void setcolors(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - __u8 blue, red; - - if (sd->colors >= 32) { - red = 32 + (sd->colors - 32) / 2; - blue = 64 - sd->colors; - } else { - red = sd->colors; - blue = 32 + (32 - sd->colors) / 2; + int i, v; + __u8 reg8a[12]; /* U & V gains */ + static __s16 uv[6] = { /* same as reg84 in signed decimal */ + -24, -38, 64, /* UR UG UB */ + 62, -51, -9 /* VR VG VB */ + }; + for (i = 0; i < 6; i++) { + v = uv[i] * sd->colors / COLOR_DEF; + reg8a[i * 2] = v; + reg8a[i * 2 + 1] = (v >> 8) & 0x0f; } - reg_w1(gspca_dev, 0x05, red); + reg_w(gspca_dev, 0x8a, reg8a, sizeof reg8a); +} + +static void setredblue(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + + reg_w1(gspca_dev, 0x05, sd->red); /* reg_w1(gspca_dev, 0x07, 32); */ - reg_w1(gspca_dev, 0x06, blue); + reg_w1(gspca_dev, 0x06, sd->blue); } static void setautogain(struct gspca_dev *gspca_dev) @@ -1300,9 +1327,9 @@ static int sd_start(struct gspca_dev *gspca_dev) } reg_w1(gspca_dev, 0x17, reg17); /* set reg1 was here */ - reg_w1(gspca_dev, 0x05, sn9c1xx[5]); - reg_w1(gspca_dev, 0x07, sn9c1xx[7]); - reg_w1(gspca_dev, 0x06, sn9c1xx[6]); + reg_w1(gspca_dev, 0x05, sn9c1xx[5]); /* red */ + reg_w1(gspca_dev, 0x07, sn9c1xx[7]); /* green */ + reg_w1(gspca_dev, 0x06, sn9c1xx[6]); /* blue */ reg_w1(gspca_dev, 0x14, sn9c1xx[0x14]); reg_w(gspca_dev, 0x20, gamma_def, sizeof gamma_def); for (i = 0; i < 8; i++) @@ -1361,27 +1388,19 @@ static int sd_start(struct gspca_dev *gspca_dev) ov7648_InitSensor(gspca_dev); reg17 = 0x21; /* reg1 = 0x42; * 42 - 46? */ -/* if (mode) - ; * 320x2... - else - ; * 640x... */ break; default: /* case SENSOR_OV7660: */ ov7660_InitSensor(gspca_dev); - if (mode) { -/* reg17 = 0x21; * 320 */ -/* reg1 = 0x44; */ -/* reg1 = 0x46; (done) */ - } else { /* 640 */ - if (sd->bridge == BRIDGE_SN9C120) { + if (sd->bridge == BRIDGE_SN9C120) { + if (mode) { /* 320x240 - 160x120 */ reg17 = 0xa2; reg1 = 0x44; /* 48 Mhz, video trf eneble */ - } else { - reg17 = 0x22; - reg1 = 0x06; /* 24 Mhz, video trf eneble - * inverse power down */ } + } else { + reg17 = 0x22; + reg1 = 0x06; /* 24 Mhz, video trf eneble + * inverse power down */ } break; } @@ -1413,20 +1432,13 @@ static int sd_start(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_MI0360: setinfrared(sd); - /* fall thru */ - case SENSOR_HV7131R: - case SENSOR_MO4000: - case SENSOR_OM6802: - setbrightness(gspca_dev); - setcontrast(gspca_dev); break; case SENSOR_OV7630: setvflip(sd); - /* fall thru */ - default: /* OV76xx */ - setbrightcont(gspca_dev); break; } + setbrightness(gspca_dev); + setcontrast(gspca_dev); setautogain(gspca_dev); return 0; } @@ -1510,7 +1522,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) expotimes = 0; sd->exposure = setexposure(gspca_dev, (unsigned int) expotimes); - setcolors(gspca_dev); + setredblue(gspca_dev); break; } } @@ -1564,19 +1576,8 @@ 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) { - switch (sd->sensor) { - case SENSOR_HV7131R: - case SENSOR_MI0360: - case SENSOR_MO4000: - case SENSOR_OM6802: - setbrightness(gspca_dev); - break; - default: /* OV76xx */ - setbrightcont(gspca_dev); - break; - } - } + if (gspca_dev->streaming) + setbrightness(gspca_dev); return 0; } @@ -1593,19 +1594,8 @@ 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) { - switch (sd->sensor) { - case SENSOR_HV7131R: - case SENSOR_MI0360: - case SENSOR_MO4000: - case SENSOR_OM6802: - setcontrast(gspca_dev); - break; - default: /* OV76xx */ - setbrightcont(gspca_dev); - break; - } - } + if (gspca_dev->streaming) + setcontrast(gspca_dev); return 0; } @@ -1635,6 +1625,42 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->blue = val; + if (gspca_dev->streaming) + setredblue(gspca_dev); + return 0; +} + +static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->blue; + return 0; +} + +static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->red = val; + if (gspca_dev->streaming) + setredblue(gspca_dev); + return 0; +} + +static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->red; + return 0; +} + static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -1719,6 +1745,7 @@ static const __devinitdata struct usb_device_id device_table[] = { #endif {USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)}, {USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)}, + {USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)}, {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)}, /* bw600.inf: {USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */ diff --git a/linux/drivers/media/video/gspca/spca500.c b/linux/drivers/media/video/gspca/spca500.c index 2e1c5e50e..6b4865280 100644 --- a/linux/drivers/media/video/gspca/spca500.c +++ b/linux/drivers/media/video/gspca/spca500.c @@ -111,7 +111,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, @@ -124,7 +124,7 @@ static struct v4l2_pix_format vga_mode[] = { .priv = 0}, }; -static struct v4l2_pix_format sif_mode[] = { +static const struct v4l2_pix_format sif_mode[] = { {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 176, .sizeimage = 176 * 144 * 3 / 8 + 590, diff --git a/linux/drivers/media/video/gspca/spca501.c b/linux/drivers/media/video/gspca/spca501.c index 17dab9859..609459321 100644 --- a/linux/drivers/media/video/gspca/spca501.c +++ b/linux/drivers/media/video/gspca/spca501.c @@ -132,7 +132,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_SPCA501, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120 * 3 / 2, diff --git a/linux/drivers/media/video/gspca/spca505.c b/linux/drivers/media/video/gspca/spca505.c index c52598e94..854ed1ff5 100644 --- a/linux/drivers/media/video/gspca/spca505.c +++ b/linux/drivers/media/video/gspca/spca505.c @@ -59,7 +59,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120 * 3 / 2, diff --git a/linux/drivers/media/video/gspca/spca506.c b/linux/drivers/media/video/gspca/spca506.c index 645ee9d44..96e2512e0 100644 --- a/linux/drivers/media/video/gspca/spca506.c +++ b/linux/drivers/media/video/gspca/spca506.c @@ -110,7 +110,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120 * 3 / 2, diff --git a/linux/drivers/media/video/gspca/spca508.c b/linux/drivers/media/video/gspca/spca508.c index c9360cdb8..698d4ed95 100644 --- a/linux/drivers/media/video/gspca/spca508.c +++ b/linux/drivers/media/video/gspca/spca508.c @@ -62,7 +62,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format sif_mode[] = { +static const struct v4l2_pix_format sif_mode[] = { {160, 120, V4L2_PIX_FMT_SPCA508, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120 * 3 / 2, diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c index 4c0046cc7..499511fa0 100644 --- a/linux/drivers/media/video/gspca/spca561.c +++ b/linux/drivers/media/video/gspca/spca561.c @@ -32,22 +32,22 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - __u16 contrast; /* rev72a only */ -#define CONTRAST_MIN 0x0000 -#define CONTRAST_DEF 0x2000 -#define CONTRAST_MAX 0x3fff - __u16 exposure; /* rev12a only */ #define EXPOSURE_MIN 1 #define EXPOSURE_DEF 200 #define EXPOSURE_MAX (4095 - 900) /* see set_exposure */ + __u8 contrast; /* rev72a only */ +#define CONTRAST_MIN 0x00 +#define CONTRAST_DEF 0x20 +#define CONTRAST_MAX 0x3f + __u8 brightness; /* rev72a only */ #define BRIGHTNESS_MIN 0 -#define BRIGHTNESS_DEF 32 -#define BRIGHTNESS_MAX 63 +#define BRIGHTNESS_DEF 0x20 +#define BRIGHTNESS_MAX 0x3f - __u8 white; /* rev12a only */ + __u8 white; #define WHITE_MIN 1 #define WHITE_DEF 0x40 #define WHITE_MAX 0x7f @@ -73,7 +73,7 @@ struct sd { #define AG_CNT_START 13 }; -static struct v4l2_pix_format sif_012a_mode[] = { +static const struct v4l2_pix_format sif_012a_mode[] = { {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120, @@ -96,7 +96,7 @@ static struct v4l2_pix_format sif_012a_mode[] = { .priv = 0}, }; -static struct v4l2_pix_format sif_072a_mode[] = { +static const struct v4l2_pix_format sif_072a_mode[] = { {160, 120, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120, @@ -146,98 +146,7 @@ static struct v4l2_pix_format sif_072a_mode[] = { #define SPCA561_SNAPBIT 0x20 #define SPCA561_SNAPCTRL 0x40 -static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) -{ - int ret; - - ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), - 0, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - value, index, NULL, 0, 500); - PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value); - if (ret < 0) - PDEBUG(D_ERR, "reg write: error %d", ret); -} - -static void write_vector(struct gspca_dev *gspca_dev, - const __u16 data[][2]) -{ - struct usb_device *dev = gspca_dev->dev; - int i; - - i = 0; - while (data[i][1] != 0) { - reg_w_val(dev, data[i][1], data[i][0]); - i++; - } -} - -/* read 'len' bytes to gspca_dev->usb_buf */ -static void reg_r(struct gspca_dev *gspca_dev, - __u16 index, __u16 length) -{ - usb_control_msg(gspca_dev->dev, - usb_rcvctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, length, 500); -} - -static void reg_w_buf(struct gspca_dev *gspca_dev, - __u16 index, const __u8 *buffer, __u16 len) -{ - memcpy(gspca_dev->usb_buf, buffer, len); - usb_control_msg(gspca_dev->dev, - usb_sndctrlpipe(gspca_dev->dev, 0), - 0, /* request */ - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - 0, /* value */ - index, gspca_dev->usb_buf, len, 500); -} - -static void i2c_write(struct gspca_dev *gspca_dev, __u16 valeur, __u16 reg) -{ - int retry = 60; - __u8 DataLow; - __u8 DataHight; - - DataLow = valeur; - DataHight = valeur >> 8; - reg_w_val(gspca_dev->dev, 0x8801, reg); - reg_w_val(gspca_dev->dev, 0x8805, DataLow); - reg_w_val(gspca_dev->dev, 0x8800, DataHight); - while (retry--) { - reg_r(gspca_dev, 0x8803, 1); - if (!gspca_dev->usb_buf[0]) - break; - } -} - -static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) -{ - int retry = 60; - __u8 value; - __u8 vallsb; - - reg_w_val(gspca_dev->dev, 0x8804, 0x92); - reg_w_val(gspca_dev->dev, 0x8801, reg); - reg_w_val(gspca_dev->dev, 0x8802, (mode | 0x01)); - do { - reg_r(gspca_dev, 0x8803, 1); - if (!gspca_dev->usb_buf[0]) - break; - } while (--retry); - if (retry == 0) - return -1; - reg_r(gspca_dev, 0x8800, 1); - value = gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8805, 1); - vallsb = gspca_dev->usb_buf[0]; - return ((int) value << 8) | vallsb; -} - -static const __u16 spca561_init_data[][2] = { +static const __u16 rev72a_init_data1[][2] = { {0x0000, 0x8114}, /* Software GPIO output data */ {0x0001, 0x8114}, /* Software GPIO output data */ {0x0000, 0x8112}, /* Some kind of reset */ @@ -247,44 +156,26 @@ static const __u16 spca561_init_data[][2] = { {0x0001, 0x8118}, /* Conf sensor */ {0x0092, 0x8804}, /* I know nothing about these */ {0x0010, 0x8802}, /* 0x88xx registers, so I won't */ - /***************/ {0x000d, 0x8805}, /* sensor default setting */ - {0x0001, 0x8801}, /* 1 <- 0x0d */ - {0x0000, 0x8800}, - {0x0018, 0x8805}, - {0x0002, 0x8801}, /* 2 <- 0x18 */ - {0x0000, 0x8800}, - {0x0065, 0x8805}, - {0x0004, 0x8801}, /* 4 <- 0x01 0x65 */ - {0x0001, 0x8800}, - {0x0021, 0x8805}, - {0x0005, 0x8801}, /* 5 <- 0x21 */ - {0x0000, 0x8800}, - {0x00aa, 0x8805}, - {0x0007, 0x8801}, /* 7 <- 0xaa */ - {0x0000, 0x8800}, - {0x0004, 0x8805}, - {0x0020, 0x8801}, /* 0x20 <- 0x15 0x04 */ - {0x0015, 0x8800}, - {0x0002, 0x8805}, - {0x0039, 0x8801}, /* 0x39 <- 0x02 */ - {0x0000, 0x8800}, - {0x0010, 0x8805}, - {0x0035, 0x8801}, /* 0x35 <- 0x10 */ - {0x0000, 0x8800}, - {0x0049, 0x8805}, - {0x0009, 0x8801}, /* 0x09 <- 0x10 0x49 */ - {0x0010, 0x8800}, - {0x000b, 0x8805}, - {0x0028, 0x8801}, /* 0x28 <- 0x0b */ - {0x0000, 0x8800}, - {0x000f, 0x8805}, - {0x003b, 0x8801}, /* 0x3b <- 0x0f */ - {0x0000, 0x8800}, - {0x0000, 0x8805}, - {0x003c, 0x8801}, /* 0x3c <- 0x00 */ - {0x0000, 0x8800}, - /***************/ + {} +}; +static const __u16 rev72a_init_sensor1[][2] = { + /* ms-win values */ + {0x0001, 0x0018}, /* 0x01 <- 0x0d */ + {0x0002, 0x0065}, /* 0x02 <- 0x18 */ + {0x0004, 0x0121}, /* 0x04 <- 0x0165 */ + {0x0005, 0x00aa}, /* 0x05 <- 0x21 */ + {0x0007, 0x0004}, /* 0x07 <- 0xaa */ + {0x0020, 0x1502}, /* 0x20 <- 0x1504 */ + {0x0039, 0x0010}, /* 0x39 <- 0x02 */ + {0x0035, 0x0049}, /* 0x35 <- 0x10 */ + {0x0009, 0x100b}, /* 0x09 <- 0x1049 */ + {0x0028, 0x000f}, /* 0x28 <- 0x0b */ + {0x003b, 0x003c}, /* 0x3b <- 0x0f */ + {0x003c, 0x0000}, /* 0x3c <- 0x00 */ + {} +}; +static const __u16 rev72a_init_data2[][2] = { {0x0018, 0x8601}, /* Pixel/line selection for color separation */ {0x0000, 0x8602}, /* Optical black level for user setting */ {0x0060, 0x8604}, /* Optical black horizontal offset */ @@ -309,10 +200,18 @@ static const __u16 spca561_init_data[][2] = { {0x0004, 0x8612}, /* Gr offset for white balance */ {0x0007, 0x8613}, /* B offset for white balance */ {0x0000, 0x8614}, /* Gb offset for white balance */ +#if 1 +/* from ms-win */ + {0x0035, 0x8651}, /* R gain for white balance */ + {0x0040, 0x8652}, /* Gr gain for white balance */ + {0x005f, 0x8653}, /* B gain for white balance */ + {0x0040, 0x8654}, /* Gb gain for white balance */ +#else {0x008c, 0x8651}, /* R gain for white balance */ {0x008c, 0x8652}, /* Gr gain for white balance */ {0x00b5, 0x8653}, /* B gain for white balance */ {0x008c, 0x8654}, /* Gb gain for white balance */ +#endif {0x0002, 0x8502}, /* Maximum average bit rate stuff */ {0x0011, 0x8802}, @@ -324,29 +223,22 @@ static const __u16 spca561_init_data[][2] = { {0x0002, 0x865b}, /* Horizontal offset for valid pixels */ {0x0003, 0x865c}, /* Vertical offset for valid lines */ - /***************//* sensor active */ - {0x0003, 0x8801}, /* 0x03 <- 0x01 0x21 //289 */ - {0x0021, 0x8805}, - {0x0001, 0x8800}, - {0x0004, 0x8801}, /* 0x04 <- 0x01 0x65 //357 */ - {0x0065, 0x8805}, - {0x0001, 0x8800}, - {0x0005, 0x8801}, /* 0x05 <- 0x2f */ - {0x002f, 0x8805}, - {0x0000, 0x8800}, - {0x0006, 0x8801}, /* 0x06 <- 0 */ - {0x0000, 0x8805}, - {0x0000, 0x8800}, - {0x000a, 0x8801}, /* 0x0a <- 2 */ - {0x0002, 0x8805}, - {0x0000, 0x8800}, - {0x0009, 0x8801}, /* 0x09 <- 0x1061 */ - {0x0061, 0x8805}, - {0x0010, 0x8800}, - {0x0035, 0x8801}, /* 0x35 <-0x14 */ - {0x0014, 0x8805}, - {0x0000, 0x8800}, + {} +}; +static const __u16 rev72a_init_sensor2[][2] = { + /* ms-win values */ + {0x0003, 0x0121}, /* 0x03 <- 0x01 0x21 //289 */ + {0x0004, 0x0165}, /* 0x04 <- 0x01 0x65 //357 */ + {0x0005, 0x002f}, /* 0x05 <- 0x2f */ + {0x0006, 0x0000}, /* 0x06 <- 0 */ + {0x000a, 0x0002}, /* 0x0a <- 2 */ + {0x0009, 0x1061}, /* 0x09 <- 0x1061 */ + {0x0035, 0x0014}, /* 0x35 <- 0x14 */ + {} +}; +static const __u16 rev72a_init_data3[][2] = { {0x0030, 0x8112}, /* ISO and drop packet enable */ +/*fixme: should stop here*/ {0x0000, 0x8112}, /* Some kind of reset ???? */ {0x0009, 0x8118}, /* Enable sensor and set standby */ {0x0000, 0x8114}, /* Software GPIO output data */ @@ -434,21 +326,6 @@ static const __u16 spca561_init_data[][2] = { {} }; -#if 0 -static void sensor_reset(struct gspca_dev *gspca_dev) -{ - reg_w_val(gspca_dev->dev, 0x8631, 0xc8); - reg_w_val(gspca_dev->dev, 0x8634, 0xc8); - reg_w_val(gspca_dev->dev, 0x8112, 0x00); - reg_w_val(gspca_dev->dev, 0x8114, 0x00); - reg_w_val(gspca_dev->dev, 0x8118, 0x21); - reg_w_val(gspca_dev->dev, 0x8804, 0x92); /* i2c init */ - reg_w_val(gspca_dev->dev, 0x8802, 0x14); - i2c_write(gspca_dev, 0x0001, 0x0d); - i2c_write(gspca_dev, 0x0000, 0x0d); -} -#endif - /******************** QC Express etch2 stuff ********************/ static const __u16 Pb100_1map8300[][2] = { /* reg, value */ @@ -529,22 +406,112 @@ static const __u16 spca561_161rev12A_data2[][2] = { {} }; -static void sensor_mapwrite(struct gspca_dev *gspca_dev, - const __u16 sensormap[][2]) +static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value) +{ + int ret; + + ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + value, index, NULL, 0, 500); + PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value); + if (ret < 0) + PDEBUG(D_ERR, "reg write: error %d", ret); +} + +static void write_vector(struct gspca_dev *gspca_dev, + const __u16 data[][2]) { - int i = 0; - __u8 usbval[2]; + struct usb_device *dev = gspca_dev->dev; + int i; - while (sensormap[i][0]) { - usbval[0] = sensormap[i][1]; - usbval[1] = sensormap[i][1] >> 8; - reg_w_buf(gspca_dev, sensormap[i][0], usbval, 2); + i = 0; + while (data[i][1] != 0) { + reg_w_val(dev, data[i][1], data[i][0]); i++; } } + +/* read 'len' bytes to gspca_dev->usb_buf */ +static void reg_r(struct gspca_dev *gspca_dev, + __u16 index, __u16 length) +{ + usb_control_msg(gspca_dev->dev, + usb_rcvctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, length, 500); +} + +/* write 'len' bytes from gspca_dev->usb_buf */ +static void reg_w_buf(struct gspca_dev *gspca_dev, + __u16 index, __u16 len) +{ + usb_control_msg(gspca_dev->dev, + usb_sndctrlpipe(gspca_dev->dev, 0), + 0, /* request */ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, /* value */ + index, gspca_dev->usb_buf, len, 500); +} + +static void i2c_write(struct gspca_dev *gspca_dev, __u16 value, __u16 reg) +{ + int retry = 60; + + reg_w_val(gspca_dev->dev, 0x8801, reg); + reg_w_val(gspca_dev->dev, 0x8805, value); + reg_w_val(gspca_dev->dev, 0x8800, value >> 8); + do { + reg_r(gspca_dev, 0x8803, 1); + if (!gspca_dev->usb_buf[0]) + return; + } while (--retry); +} + +static int i2c_read(struct gspca_dev *gspca_dev, __u16 reg, __u8 mode) +{ + int retry = 60; + __u8 value; + + reg_w_val(gspca_dev->dev, 0x8804, 0x92); + reg_w_val(gspca_dev->dev, 0x8801, reg); + reg_w_val(gspca_dev->dev, 0x8802, mode | 0x01); + do { + reg_r(gspca_dev, 0x8803, 1); + if (!gspca_dev->usb_buf[0]) { + reg_r(gspca_dev, 0x8800, 1); + value = gspca_dev->usb_buf[0]; + reg_r(gspca_dev, 0x8805, 1); + return ((int) value << 8) | gspca_dev->usb_buf[0]; + } + } while (--retry); + return -1; +} + +static void sensor_mapwrite(struct gspca_dev *gspca_dev, + const __u16 (*sensormap)[2]) +{ + while ((*sensormap)[0]) { + gspca_dev->usb_buf[0] = (*sensormap)[1]; + gspca_dev->usb_buf[1] = (*sensormap)[1] >> 8; + reg_w_buf(gspca_dev, (*sensormap)[0], 2); + sensormap++; + } +} + +static void write_sensor_72a(struct gspca_dev *gspca_dev, + const __u16 (*sensor)[2]) +{ + while ((*sensor)[0]) { + i2c_write(gspca_dev, (*sensor)[1], (*sensor)[0]); + sensor++; + } +} + static void init_161rev12A(struct gspca_dev *gspca_dev) { -/* sensor_reset(gspca_dev); (not in win) */ write_vector(gspca_dev, spca561_161rev12A_data1); sensor_mapwrite(gspca_dev, Pb100_1map8300); /*fixme: should be in sd_start*/ @@ -612,49 +579,68 @@ static int sd_init_12a(struct gspca_dev *gspca_dev) static int sd_init_72a(struct gspca_dev *gspca_dev) { PDEBUG(D_STREAM, "Chip revision: 072a"); - write_vector(gspca_dev, spca561_init_data); + write_vector(gspca_dev, rev72a_init_data1); + write_sensor_72a(gspca_dev, rev72a_init_sensor1); + write_vector(gspca_dev, rev72a_init_data2); + write_sensor_72a(gspca_dev, rev72a_init_sensor2); + write_vector(gspca_dev, rev72a_init_data3); return 0; } -static void setcontrast(struct gspca_dev *gspca_dev) +/* rev 72a only */ +static void setbrightness(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; struct usb_device *dev = gspca_dev->dev; - __u8 lowb; + __u8 value; - switch (sd->chip_revision) { - case Rev072A: - lowb = sd->contrast >> 8; - reg_w_val(dev, 0x8651, lowb); - reg_w_val(dev, 0x8652, lowb); - reg_w_val(dev, 0x8653, lowb); - reg_w_val(dev, 0x8654, lowb); - break; - default: { -/* case Rev012A: { */ - static const __u8 Reg8391[] = - { 0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00 }; + value = sd->brightness; - reg_w_buf(gspca_dev, 0x8391, Reg8391, 8); - reg_w_buf(gspca_dev, 0x8390, Reg8391, 8); - break; - } - } + /* offsets for white balance */ + reg_w_val(dev, 0x8611, value); /* R */ + reg_w_val(dev, 0x8612, value); /* Gr */ + reg_w_val(dev, 0x8613, value); /* B */ + reg_w_val(dev, 0x8614, value); /* Gb */ } -/* rev12a only */ static void setwhite(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; __u16 white; - __u8 reg8614, reg8616; + __u8 blue, red; + __u16 reg; - white = sd->white; /* try to emulate MS-win as possible */ - reg8616 = 0x90 - white * 5 / 8; - reg_w_val(gspca_dev->dev, 0x8616, reg8616); - reg8614 = 0x20 + white * 3 / 8; - reg_w_val(gspca_dev->dev, 0x8614, reg8614); + white = sd->white; + red = 0x20 + white * 3 / 8; + blue = 0x90 - white * 5 / 8; + if (sd->chip_revision == Rev012A) { + reg = 0x8614; + } else { + reg = 0x8651; + red += sd->contrast - 0x20; + blue += sd->contrast - 0x20; + } + reg_w_val(gspca_dev->dev, reg, red); + reg_w_val(gspca_dev->dev, reg + 2, blue); +} + +static void setcontrast(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct usb_device *dev = gspca_dev->dev; + __u8 value; + + if (sd->chip_revision != Rev072A) + return; + value = sd->contrast + 0x20; + + /* gains for white balance */ + setwhite(gspca_dev); +/* reg_w_val(dev, 0x8651, value); * R - done by setwhite */ + reg_w_val(dev, 0x8652, value); /* Gr */ +/* reg_w_val(dev, 0x8653, value); * B - done by setwhite */ + reg_w_val(dev, 0x8654, value); /* Gb */ } /* rev 12a only */ @@ -663,7 +649,6 @@ static void setexposure(struct gspca_dev *gspca_dev) struct sd *sd = (struct sd *) gspca_dev; int expo; int clock_divider; - __u8 data[2]; /* Register 0x8309 controls exposure for the spca561, the basic exposure setting goes from 1-2047, where 1 is completely @@ -687,20 +672,19 @@ static void setexposure(struct gspca_dev *gspca_dev) clock_divider = 3; } expo |= clock_divider << 11; - data[0] = expo; - data[1] = expo >> 8; - reg_w_buf(gspca_dev, 0x8309, data, 2); + gspca_dev->usb_buf[0] = expo; + gspca_dev->usb_buf[1] = expo >> 8; + reg_w_buf(gspca_dev, 0x8309, 2); } /* rev 12a only */ static void setgain(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; - __u8 data[2]; - data[0] = sd->gain; - data[1] = 0; - reg_w_buf(gspca_dev, 0x8335, data, 2); + gspca_dev->usb_buf[0] = sd->gain; + gspca_dev->usb_buf[1] = 0; + reg_w_buf(gspca_dev, 0x8335, 2); } static void setautogain(struct gspca_dev *gspca_dev) @@ -716,9 +700,9 @@ static void setautogain(struct gspca_dev *gspca_dev) static int sd_start_12a(struct gspca_dev *gspca_dev) { struct usb_device *dev = gspca_dev->dev; - int Clck = 0x8a; /* lower 0x8X values lead to fps > 30 */ - __u8 Reg8307[] = { 0xaa, 0x00 }; int mode; + static const __u8 Reg8391[8] = + {0x92, 0x30, 0x20, 0x00, 0x0c, 0x00, 0x00, 0x00}; mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; if (mode <= 1) { @@ -730,14 +714,21 @@ static int sd_start_12a(struct gspca_dev *gspca_dev) * is sufficient to push raw frames at ~20fps */ reg_w_val(dev, 0x8500, mode); } /* -- qq@kuku.eu.org */ - reg_w_buf(gspca_dev, 0x8307, Reg8307, 2); - reg_w_val(gspca_dev->dev, 0x8700, Clck); + + gspca_dev->usb_buf[0] = 0xaa; + gspca_dev->usb_buf[1] = 0x00; + reg_w_buf(gspca_dev, 0x8307, 2); + /* clock - lower 0x8X values lead to fps > 30 */ + reg_w_val(gspca_dev->dev, 0x8700, 0x8a); /* 0x8f 0x85 0x27 clock */ reg_w_val(gspca_dev->dev, 0x8112, 0x1e | 0x20); reg_w_val(gspca_dev->dev, 0x850b, 0x03); - setcontrast(gspca_dev); + memcpy(gspca_dev->usb_buf, Reg8391, 8); + reg_w_buf(gspca_dev, 0x8391, 8); + reg_w_buf(gspca_dev, 0x8390, 8); setwhite(gspca_dev); setautogain(gspca_dev); +/* setgain(gspca_dev); */ setexposure(gspca_dev); return 0; } @@ -764,6 +755,9 @@ static int sd_start_72a(struct gspca_dev *gspca_dev) reg_w_val(dev, 0x8500, mode); /* mode */ reg_w_val(dev, 0x8700, Clck); /* 0x27 clock */ reg_w_val(dev, 0x8112, 0x10 | 0x20); + setcontrast(gspca_dev); +/* setbrightness(gspca_dev); * fixme: bad values */ + setwhite(gspca_dev); setautogain(gspca_dev); return 0; } @@ -805,7 +799,6 @@ static void do_autogain(struct gspca_dev *gspca_dev) __u8 luma_mean = 110; __u8 luma_delta = 20; __u8 spring = 4; - __u8 reg8339[2]; if (sd->ag_cnt < 0) return; @@ -848,13 +841,13 @@ static void do_autogain(struct gspca_dev *gspca_dev) if (gainG > 0x3f) gainG = 0x3f; - else if (gainG < 4) + else if (gainG < 3) gainG = 3; i2c_write(gspca_dev, gainG, 0x35); - if (expotimes >= 0x0256) + if (expotimes > 0x0256) expotimes = 0x0256; - else if (expotimes < 4) + else if (expotimes < 3) expotimes = 3; i2c_write(gspca_dev, expotimes | pixelclk, 0x09); } @@ -862,13 +855,13 @@ static void do_autogain(struct gspca_dev *gspca_dev) case Rev012A: reg_r(gspca_dev, 0x8330, 2); if (gspca_dev->usb_buf[1] > 0x08) { - reg8339[0] = ++sd->expo12a; - reg8339[1] = 0; - reg_w_buf(gspca_dev, 0x8339, reg8339, 2); + gspca_dev->usb_buf[0] = ++sd->expo12a; + gspca_dev->usb_buf[1] = 0; + reg_w_buf(gspca_dev, 0x8339, 2); } else if (gspca_dev->usb_buf[1] < 0x02) { - reg8339[0] = --sd->expo12a; - reg8339[1] = 0; - reg_w_buf(gspca_dev, 0x8339, reg8339, 2); + gspca_dev->usb_buf[0] = --sd->expo12a; + gspca_dev->usb_buf[1] = 0; + reg_w_buf(gspca_dev, 0x8339, 2); } break; } @@ -881,8 +874,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, { struct sd *sd = (struct sd *) gspca_dev; - switch (data[0]) { - case 0: /* start of frame */ + switch (data[0]) { /* sequence number */ + case 0: /* start of frame */ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0); data += SPCA561_OFFSET_DATA; @@ -904,8 +897,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, frame, data, len); } return; - case 0xff: /* drop */ -/* gspca_dev->last_packet_type = DISCARD_PACKET; */ + case 0xff: /* drop (empty mpackets) */ return; } data++; @@ -914,55 +906,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, } /* rev 72a only */ -static void setbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u8 value; - - value = sd->brightness; - reg_w_val(gspca_dev->dev, 0x8611, value); - reg_w_val(gspca_dev->dev, 0x8612, value); - reg_w_val(gspca_dev->dev, 0x8613, value); - reg_w_val(gspca_dev->dev, 0x8614, value); -} - -static void getbrightness(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u16 tot; - - tot = 0; - reg_r(gspca_dev, 0x8611, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8612, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8613, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8614, 1); - tot += gspca_dev->usb_buf[0]; - sd->brightness = tot >> 2; -} - -/* rev72a only */ -static void getcontrast(struct gspca_dev *gspca_dev) -{ - struct sd *sd = (struct sd *) gspca_dev; - __u16 tot; - - tot = 0; - reg_r(gspca_dev, 0x8651, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8652, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8653, 1); - tot += gspca_dev->usb_buf[0]; - reg_r(gspca_dev, 0x8654, 1); - tot += gspca_dev->usb_buf[0]; - sd->contrast = tot << 6; - PDEBUG(D_CONF, "get contrast %d", sd->contrast); -} - -/* rev 72a only */ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -977,7 +920,6 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - getbrightness(gspca_dev); *val = sd->brightness; return 0; } @@ -997,7 +939,6 @@ static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - getcontrast(gspca_dev); *val = sd->contrast; return 0; } @@ -1020,7 +961,6 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) return 0; } -/* rev12a only */ static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; @@ -1135,6 +1075,19 @@ static struct ctrl sd_ctrls_12a[] = { static struct ctrl sd_ctrls_72a[] = { { + { + .id = V4L2_CID_DO_WHITE_BALANCE, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "White Balance", + .minimum = WHITE_MIN, + .maximum = WHITE_MAX, + .step = 1, + .default_value = WHITE_DEF, + }, + .set = sd_setwhite, + .get = sd_getwhite, + }, + { { .id = V4L2_CID_BRIGHTNESS, .type = V4L2_CTRL_TYPE_INTEGER, diff --git a/linux/drivers/media/video/gspca/stk014.c b/linux/drivers/media/video/gspca/stk014.c index d9d64911f..60de9af87 100644 --- a/linux/drivers/media/video/gspca/stk014.c +++ b/linux/drivers/media/video/gspca/stk014.c @@ -109,7 +109,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, @@ -424,10 +424,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, /* beginning of the frame */ #define STKHDRSZ 12 - gspca_frame_add(gspca_dev, INTER_PACKET, frame, - data + STKHDRSZ, len - STKHDRSZ); -#undef STKHDRSZ - return; + data += STKHDRSZ; + len -= STKHDRSZ; } gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } diff --git a/linux/drivers/media/video/gspca/stv06xx/Kconfig b/linux/drivers/media/video/gspca/stv06xx/Kconfig new file mode 100644 index 000000000..634ad38d9 --- /dev/null +++ b/linux/drivers/media/video/gspca/stv06xx/Kconfig @@ -0,0 +1,9 @@ +config USB_STV06XX + tristate "STV06XX USB Camera Driver" + depends on USB_GSPCA + help + Say Y here if you want support for cameras based on + the ST STV06XX chip. + + To compile this driver as a module, choose M here: the + module will be called gspca_stv06xx. diff --git a/linux/drivers/media/video/gspca/stv06xx/Makefile b/linux/drivers/media/video/gspca/stv06xx/Makefile new file mode 100644 index 000000000..feeaa94ab --- /dev/null +++ b/linux/drivers/media/video/gspca/stv06xx/Makefile @@ -0,0 +1,9 @@ +obj-$(CONFIG_USB_STV06XX) += gspca_stv06xx.o + +gspca_stv06xx-objs := stv06xx.o \ + stv06xx_vv6410.o \ + stv06xx_hdcs.o \ + stv06xx_pb0100.o + +EXTRA_CFLAGS += -Idrivers/media/video/gspca + diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx.c new file mode 100644 index 000000000..13a021e3c --- /dev/null +++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx.c @@ -0,0 +1,522 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#include "stv06xx_sensor.h" + +MODULE_AUTHOR("Erik Andrén"); +MODULE_DESCRIPTION("STV06XX USB Camera Driver"); +MODULE_LICENSE("GPL"); + +static int dump_bridge; +static int dump_sensor; + +int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data) +{ + int err; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + u8 len = (i2c_data > 0xff) ? 2 : 1; + + buf[0] = i2c_data & 0xff; + buf[1] = (i2c_data >> 8) & 0xff; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, address, 0, buf, len, + STV06XX_URB_MSG_TIMEOUT); + + + PDEBUG(D_CONF, "Written 0x%x to address 0x%x, status: %d", + i2c_data, address, err); + + return (err < 0) ? err : 0; +} + +int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data) +{ + int err; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x04, 0xc0, address, 0, buf, 1, + STV06XX_URB_MSG_TIMEOUT); + + *i2c_data = buf[0]; + + PDEBUG(D_CONF, "Read 0x%x from address 0x%x, status %d", + *i2c_data, address, err); + + return (err < 0) ? err : 0; +} + +/* Wraps the normal write sensor bytes / words functions for writing a + single value */ +int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value) +{ + if (sd->sensor->i2c_len == 2) { + u16 data[2] = { address, value }; + return stv06xx_write_sensor_words(sd, data, 1); + } else { + u8 data[2] = { address, value }; + return stv06xx_write_sensor_bytes(sd, data, 1); + } +} + +static int stv06xx_write_sensor_finish(struct sd *sd) +{ + int err = 0; + + if (IS_850(sd)) { + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + /* Quickam Web needs an extra packet */ + buf[0] = 0; + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x1704, 0, buf, 1, + STV06XX_URB_MSG_TIMEOUT); + } + + return (err < 0) ? err : 0; +} + +int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len) +{ + int err, i, j; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len); + for (i = 0; i < len;) { + /* Build the command buffer */ + memset(buf, 0, I2C_BUFFER_LENGTH); + for (j = 0; j < I2C_MAX_BYTES && i < len; j++, i++) { + buf[j] = data[2*i]; + buf[0x10 + j] = data[2*i+1]; + PDEBUG(D_USBO, "I2C: Writing 0x%02x to reg 0x%02x", + data[2*i+1], data[2*i]); + } + buf[0x20] = sd->sensor->i2c_addr; + buf[0x21] = j - 1; /* Number of commands to send - 1 */ + buf[0x22] = I2C_WRITE_CMD; + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x0400, 0, buf, + I2C_BUFFER_LENGTH, + STV06XX_URB_MSG_TIMEOUT); + if (err < 0) + return err; + } + return stv06xx_write_sensor_finish(sd); +} + +int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len) +{ + int err, i, j; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len); + + for (i = 0; i < len;) { + /* Build the command buffer */ + memset(buf, 0, I2C_BUFFER_LENGTH); + for (j = 0; j < I2C_MAX_WORDS && i < len; j++, i++) { + buf[j] = data[2*i]; + buf[0x10 + j * 2] = data[2*i+1]; + buf[0x10 + j * 2 + 1] = data[2*i+1] >> 8; + PDEBUG(D_USBO, "I2C: Writing 0x%04x to reg 0x%02x", + data[2*i+1], data[2*i]); + } + buf[0x20] = sd->sensor->i2c_addr; + buf[0x21] = j - 1; /* Number of commands to send - 1 */ + buf[0x22] = I2C_WRITE_CMD; + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x0400, 0, buf, + I2C_BUFFER_LENGTH, + STV06XX_URB_MSG_TIMEOUT); + if (err < 0) + return err; + } + return stv06xx_write_sensor_finish(sd); +} + +int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value) +{ + int err; + struct usb_device *udev = sd->gspca_dev.dev; + __u8 *buf = sd->gspca_dev.usb_buf; + + err = stv06xx_write_bridge(sd, STV_I2C_FLUSH, sd->sensor->i2c_flush); + if (err < 0) + return err; + + /* Clear mem */ + memset(buf, 0, I2C_BUFFER_LENGTH); + + buf[0] = address; + buf[0x20] = sd->sensor->i2c_addr; + buf[0x21] = 0; + + /* Read I2C register */ + buf[0x22] = I2C_READ_CMD; + + err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + 0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH, + STV06XX_URB_MSG_TIMEOUT); + if (err < 0) { + PDEBUG(D_ERR, "I2C Read: error writing address: %d", err); + return err; + } + + err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), + 0x04, 0xc0, 0x1410, 0, buf, sd->sensor->i2c_len, + STV06XX_URB_MSG_TIMEOUT); + if (sd->sensor->i2c_len == 2) + *value = buf[0] | (buf[1] << 8); + else + *value = buf[0]; + + PDEBUG(D_USBO, "I2C: Read 0x%x from address 0x%x, status: %d", + *value, address, err); + + return (err < 0) ? err : 0; +} + +/* Dumps all bridge registers */ +static void stv06xx_dump_bridge(struct sd *sd) +{ + int i; + u8 data, buf; + + info("Dumping all stv06xx bridge registers"); + for (i = 0x1400; i < 0x160f; i++) { + stv06xx_read_bridge(sd, i, &data); + + info("Read 0x%x from address 0x%x", data, i); + } + + for (i = 0x1400; i < 0x160f; i++) { + stv06xx_read_bridge(sd, i, &data); + buf = data; + + stv06xx_write_bridge(sd, i, 0xff); + stv06xx_read_bridge(sd, i, &data); + if (data == 0xff) + info("Register 0x%x is read/write", i); + else if (data != buf) + info("Register 0x%x is read/write," + "but only partially", i); + else + info("Register 0x%x is read-only", i); + + stv06xx_write_bridge(sd, i, buf); + } +} + +/* this function is called at probe and resume time */ +static int stv06xx_init(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err; + + PDEBUG(D_PROBE, "Initializing camera"); + + /* Let the usb init settle for a bit + before performing the initialization */ + msleep(250); + + err = sd->sensor->init(sd); + + if (dump_sensor) + sd->sensor->dump(sd); + + return (err < 0) ? err : 0; +} + +/* Start the camera */ +static int stv06xx_start(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err; + + /* Prepare the sensor for start */ + err = sd->sensor->start(sd); + if (err < 0) + goto out; + + /* Start isochronous streaming */ + err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 1); + +out: + if (err < 0) + PDEBUG(D_STREAM, "Starting stream failed"); + else + PDEBUG(D_STREAM, "Started streaming"); + + return (err < 0) ? err : 0; +} + +static void stv06xx_stopN(struct gspca_dev *gspca_dev) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + + /* stop ISO-streaming */ + err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 0); + if (err < 0) + goto out; + + err = sd->sensor->stop(sd); + if (err < 0) + goto out; + +out: + if (err < 0) + PDEBUG(D_STREAM, "Failed to stop stream"); + else + PDEBUG(D_STREAM, "Stopped streaming"); +} + +/* + * Analyse an USB packet of the data stream and store it appropriately. + * Each packet contains an integral number of chunks. Each chunk has + * 2-bytes identification, followed by 2-bytes that describe the chunk + * length. Known/guessed chunk identifications are: + * 8001/8005/C001/C005 - Begin new frame + * 8002/8006/C002/C006 - End frame + * 0200/4200 - Contains actual image data, bayer or compressed + * 0005 - 11 bytes of unknown data + * 0100 - 2 bytes of unknown data + * The 0005 and 0100 chunks seem to appear only in compressed stream. + */ +static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, + struct gspca_frame *frame, /* target */ + __u8 *data, /* isoc packet */ + int len) /* iso packet length */ +{ + PDEBUG(D_PACK, "Packet of length %d arrived", len); + + /* A packet may contain several frames + loop until the whole packet is reached */ + while (len) { + int id, chunk_len; + + if (len < 4) { + PDEBUG(D_PACK, "Packet is smaller than 4 bytes"); + return; + } + + /* Capture the id */ + id = (data[0] << 8) | data[1]; + + /* Capture the chunk length */ + chunk_len = (data[2] << 8) | data[3]; + PDEBUG(D_PACK, "Chunk id: %x, length: %d", id, chunk_len); + + data += 4; + len -= 4; + + if (len < chunk_len) { + PDEBUG(D_ERR, "URB packet length is smaller" + " than the specified chunk length"); + return; + } + + switch (id) { + case 0x0200: + case 0x4200: + PDEBUG(D_PACK, "Frame data packet detected"); + + gspca_frame_add(gspca_dev, INTER_PACKET, frame, + data, chunk_len); + break; + + case 0x8001: + case 0x8005: + case 0xc001: + case 0xc005: + PDEBUG(D_PACK, "Starting new frame"); + + /* Create a new frame, chunk length should be zero */ + gspca_frame_add(gspca_dev, FIRST_PACKET, + frame, data, 0); + + if (chunk_len) + PDEBUG(D_ERR, "Chunk length is " + "non-zero on a SOF"); + break; + + case 0x8002: + case 0x8006: + case 0xc002: + PDEBUG(D_PACK, "End of frame detected"); + + /* Complete the last frame (if any) */ + gspca_frame_add(gspca_dev, LAST_PACKET, frame, data, 0); + + if (chunk_len) + PDEBUG(D_ERR, "Chunk length is " + "non-zero on a EOF"); + break; + + case 0x0005: + PDEBUG(D_PACK, "Chunk 0x005 detected"); + /* Unknown chunk with 11 bytes of data, + occurs just before end of each frame + in compressed mode */ + break; + + case 0x0100: + PDEBUG(D_PACK, "Chunk 0x0100 detected"); + /* Unknown chunk with 2 bytes of data, + occurs 2-3 times per USB interrupt */ + break; + default: + PDEBUG(D_PACK, "Unknown chunk %d detected", id); + /* Unknown chunk */ + } + data += chunk_len; + len -= chunk_len; + } +} + +static int stv06xx_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id); + +/* sub-driver description */ +static const struct sd_desc sd_desc = { + .name = MODULE_NAME, + .config = stv06xx_config, + .init = stv06xx_init, + .start = stv06xx_start, + .stopN = stv06xx_stopN, + .pkt_scan = stv06xx_pkt_scan +}; + +/* This function is called at probe time */ +static int stv06xx_config(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + PDEBUG(D_PROBE, "Configuring camera"); + + cam = &gspca_dev->cam; + cam->epaddr = STV_ISOC_ENDPOINT_ADDR; + sd->desc = sd_desc; + gspca_dev->sd_desc = &sd->desc; + + if (dump_bridge) + stv06xx_dump_bridge(sd); + + sd->sensor = &stv06xx_sensor_vv6410; + if (!sd->sensor->probe(sd)) + return 0; + + sd->sensor = &stv06xx_sensor_hdcs1x00; + if (!sd->sensor->probe(sd)) + return 0; + + sd->sensor = &stv06xx_sensor_hdcs1020; + if (!sd->sensor->probe(sd)) + return 0; + + sd->sensor = &stv06xx_sensor_pb0100; + if (!sd->sensor->probe(sd)) + return 0; + + sd->sensor = NULL; + return -ENODEV; +} + + + +/* -- module initialisation -- */ +static const __devinitdata struct usb_device_id device_table[] = { + {USB_DEVICE(0x046d, 0x0840)}, /* QuickCam Express */ + {USB_DEVICE(0x046d, 0x0850)}, /* LEGO cam / QuickCam Web */ + {USB_DEVICE(0x046d, 0x0870)}, /* Dexxa WebCam USB */ + {} +}; +MODULE_DEVICE_TABLE(usb, device_table); + +/* -- device connect -- */ +static int sd_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + PDEBUG(D_PROBE, "Probing for a stv06xx device"); + return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), + THIS_MODULE); +} + +static void sd_disconnect(struct usb_interface *intf) +{ + struct gspca_dev *gspca_dev = usb_get_intfdata(intf); + struct sd *sd = (struct sd *) gspca_dev; + PDEBUG(D_PROBE, "Disconnecting the stv06xx device"); + + if (sd->sensor->disconnect) + sd->sensor->disconnect(sd); + gspca_disconnect(intf); +} + +static struct usb_driver sd_driver = { + .name = MODULE_NAME, + .id_table = device_table, + .probe = sd_probe, + .disconnect = sd_disconnect, +#ifdef CONFIG_PM + .suspend = gspca_suspend, + .resume = gspca_resume, +#endif +}; + +/* -- module insert / remove -- */ +static int __init sd_mod_init(void) +{ + if (usb_register(&sd_driver) < 0) + return -1; + PDEBUG(D_PROBE, "registered"); + return 0; +} +static void __exit sd_mod_exit(void) +{ + usb_deregister(&sd_driver); + PDEBUG(D_PROBE, "deregistered"); +} + +module_init(sd_mod_init); +module_exit(sd_mod_exit); + +module_param(dump_bridge, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup"); + +module_param(dump_sensor, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(dump_sensor, "Dumps all sensor registers at startup"); diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx.h new file mode 100644 index 000000000..1207e7d17 --- /dev/null +++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#ifndef STV06XX_H_ +#define STV06XX_H_ + +#include "gspca.h" + +#define MODULE_NAME "STV06xx" + +#define STV_ISOC_ENDPOINT_ADDR 0x81 + +#ifndef V4L2_PIX_FMT_SGRBG8 +#define V4L2_PIX_FMT_SGRBG8 v4l2_fourcc('G', 'R', 'B', 'G') +#endif + +#define STV_REG23 0x0423 + +/* Control registers of the STV0600 ASIC */ +#define STV_I2C_PARTNER 0x1420 +#define STV_I2C_VAL_REG_VAL_PAIRS_MIN1 0x1421 +#define STV_I2C_READ_WRITE_TOGGLE 0x1422 +#define STV_I2C_FLUSH 0x1423 +#define STV_I2C_SUCC_READ_REG_VALS 0x1424 + +#define STV_ISO_ENABLE 0x1440 +#define STV_SCAN_RATE 0x1443 +#define STV_LED_CTRL 0x1445 +#define STV_STV0600_EMULATION 0x1446 +#define STV_REG00 0x1500 +#define STV_REG01 0x1501 +#define STV_REG02 0x1502 +#define STV_REG03 0x1503 +#define STV_REG04 0x1504 + +#define STV_ISO_SIZE_L 0x15c1 +#define STV_ISO_SIZE_H 0x15c2 + +/* Refers to the CIF 352x288 and QCIF 176x144 */ +/* 1: 288 lines, 2: 144 lines */ +#define STV_Y_CTRL 0x15c3 + +/* 0xa: 352 columns, 0x6: 176 columns */ +#define STV_X_CTRL 0x1680 + +#define STV06XX_URB_MSG_TIMEOUT 5000 + +#define I2C_MAX_BYTES 16 +#define I2C_MAX_WORDS 8 + +#define I2C_BUFFER_LENGTH 0x23 +#define I2C_READ_CMD 3 +#define I2C_WRITE_CMD 1 + +#define LED_ON 1 +#define LED_OFF 0 + +/* STV06xx device descriptor */ +struct sd { + struct gspca_dev gspca_dev; + + /* 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; +}; + +int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data); +int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data); + +int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len); +int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len); + +int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value); +int stv06xx_write_sensor(struct sd *sd, u8 address, u16 value); + +#endif diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c new file mode 100644 index 000000000..14335a9e4 --- /dev/null +++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c @@ -0,0 +1,535 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * Copyright (c) 2008 Chia-I Wu + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#include "stv06xx_hdcs.h" + +enum hdcs_power_state { + HDCS_STATE_SLEEP, + HDCS_STATE_IDLE, + HDCS_STATE_RUN +}; + +/* no lock? */ +struct hdcs { + enum hdcs_power_state state; + int w, h; + + /* visible area of the sensor array */ + struct { + int left, top; + int width, height; + int border; + } array; + + struct { + /* Column timing overhead */ + u8 cto; + /* Column processing overhead */ + u8 cpo; + /* Row sample period constant */ + u16 rs; + /* Exposure reset duration */ + u16 er; + } exp; + + int psmp; +}; + +static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len) +{ + u8 regs[I2C_MAX_BYTES * 2]; + int i; + + if (unlikely((len <= 0) || (len >= I2C_MAX_BYTES) || + (reg + len > 0xff))) + return -EINVAL; + + for (i = 0; i < len; i++, reg++) { + regs[2*i] = reg; + regs[2*i+1] = vals[i]; + } + + return stv06xx_write_sensor_bytes(sd, regs, len); +} + +static int hdcs_set_state(struct sd *sd, enum hdcs_power_state state) +{ + struct hdcs *hdcs = sd->sensor_priv; + u8 val; + int ret; + + if (hdcs->state == state) + return 0; + + /* we need to go idle before running or sleeping */ + if (hdcs->state != HDCS_STATE_IDLE) { + ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0); + if (ret) + return ret; + } + + hdcs->state = HDCS_STATE_IDLE; + + if (state == HDCS_STATE_IDLE) + return 0; + + switch (state) { + case HDCS_STATE_SLEEP: + val = HDCS_SLEEP_MODE; + break; + + case HDCS_STATE_RUN: + val = HDCS_RUN_ENABLE; + break; + + default: + return -EINVAL; + } + + ret = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), val); + if (ret < 0) + hdcs->state = state; + + return ret; +} + +static int hdcs_reset(struct sd *sd) +{ + struct hdcs *hdcs = sd->sensor_priv; + int err; + + err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 1); + if (err < 0) + return err; + + err = stv06xx_write_sensor(sd, HDCS_REG_CONTROL(sd), 0); + if (err < 0) + hdcs->state = HDCS_STATE_IDLE; + + 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; + + /* Column time period */ + int ct; + /* Column processing period */ + int cp; + /* Row processing period */ + int rp; + int cycles; + int err; + int rowexp; + u16 data[2]; + + err = stv06xx_read_sensor(sd, HDCS_ROWEXPL, &data[0]); + if (err < 0) + return err; + + err = stv06xx_read_sensor(sd, HDCS_ROWEXPH, &data[1]); + if (err < 0) + return err; + + rowexp = (data[1] << 8) | data[0]; + + ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2); + cp = hdcs->exp.cto + (hdcs->w * ct / 2); + rp = hdcs->exp.rs + cp; + + cycles = rp * rowexp; + *val = cycles / HDCS_CLK_FREQ_MHZ; + PDEBUG(D_V4L2, "Read exposure %d", *val); + return 0; +} + +static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct hdcs *hdcs = sd->sensor_priv; + int rowexp, srowexp; + int max_srowexp; + /* Column time period */ + int ct; + /* Column processing period */ + int cp; + /* Row processing period */ + int rp; + /* Minimum number of column timing periods + within the column processing period */ + int mnct; + int cycles, err; + u8 exp[4]; + + cycles = val * HDCS_CLK_FREQ_MHZ; + + ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2); + cp = hdcs->exp.cto + (hdcs->w * ct / 2); + + /* the cycles one row takes */ + rp = hdcs->exp.rs + cp; + + rowexp = cycles / rp; + + /* the remaining cycles */ + cycles -= rowexp * rp; + + /* calculate sub-row exposure */ + if (IS_1020(sd)) { + /* see HDCS-1020 datasheet 3.5.6.4, p. 63 */ + srowexp = hdcs->w - (cycles + hdcs->exp.er + 13) / ct; + + mnct = (hdcs->exp.er + 12 + ct - 1) / ct; + max_srowexp = hdcs->w - mnct; + } else { + /* see HDCS-1000 datasheet 3.4.5.5, p. 61 */ + srowexp = cp - hdcs->exp.er - 6 - cycles; + + mnct = (hdcs->exp.er + 5 + ct - 1) / ct; + max_srowexp = cp - mnct * ct - 1; + } + + if (srowexp < 0) + srowexp = 0; + else if (srowexp > max_srowexp) + srowexp = max_srowexp; + + if (IS_1020(sd)) { + exp[0] = rowexp & 0xff; + exp[1] = rowexp >> 8; + exp[2] = (srowexp >> 2) & 0xff; + /* this clears exposure error flag */ + exp[3] = 0x1; + err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4); + } else { + exp[0] = rowexp & 0xff; + exp[1] = rowexp >> 8; + exp[2] = srowexp & 0xff; + exp[3] = srowexp >> 8; + err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4); + if (err < 0) + return err; + + /* clear exposure error flag */ + err = stv06xx_write_sensor(sd, + HDCS_STATUS, BIT(4)); + } + PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d", + val, rowexp, srowexp); + return err; +} + +static int hdcs_set_gains(struct sd *sd, u8 r, u8 g, u8 b) +{ + u8 gains[4]; + + /* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */ + if (r > 127) + r = 0x80 | (r / 2); + if (g > 127) + g = 0x80 | (g / 2); + if (b > 127) + b = 0x80 | (b / 2); + + gains[0] = g; + gains[1] = r; + gains[2] = b; + gains[3] = g; + + return hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4); +} + +static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + int err; + u16 data; + + err = stv06xx_read_sensor(sd, HDCS_ERECPGA, &data); + + /* Bit 7 doubles the gain */ + if (data & 0x80) + *val = (data & 0x7f) * 2; + else + *val = data; + + PDEBUG(D_V4L2, "Read gain %d", *val); + return err; +} + +static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + PDEBUG(D_V4L2, "Writing gain %d", val); + return hdcs_set_gains((struct sd *) gspca_dev, + val & 0xff, val & 0xff, val & 0xff); +} + +static int hdcs_set_size(struct sd *sd, + unsigned int width, unsigned int height) +{ + struct hdcs *hdcs = sd->sensor_priv; + u8 win[4]; + unsigned int x, y; + int err; + + /* must be multiple of 4 */ + width = (width + 3) & ~0x3; + height = (height + 3) & ~0x3; + + if (width > hdcs->array.width) + width = hdcs->array.width; + + if (IS_1020(sd)) { + /* the borders are also invalid */ + if (height + 2 * hdcs->array.border + HDCS_1020_BOTTOM_Y_SKIP + > hdcs->array.height) + height = hdcs->array.height - 2 * hdcs->array.border - + HDCS_1020_BOTTOM_Y_SKIP; + + y = (hdcs->array.height - HDCS_1020_BOTTOM_Y_SKIP - height) / 2 + + hdcs->array.top; + } else { + if (height > hdcs->array.height) + height = hdcs->array.height; + + y = hdcs->array.top + (hdcs->array.height - height) / 2; + } + + x = hdcs->array.left + (hdcs->array.width - width) / 2; + + win[0] = y / 4; + win[1] = x / 4; + win[2] = (y + height) / 4 - 1; + win[3] = (x + width) / 4 - 1; + + err = hdcs_reg_write_seq(sd, HDCS_FWROW, win, 4); + if (err < 0) + return err; + + /* Update the current width and height */ + hdcs->w = width; + hdcs->h = height; + return err; +} + +static int hdcs_probe_1x00(struct sd *sd) +{ + struct hdcs *hdcs; + u16 sensor; + int ret; + + ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor); + if (ret < 0 || sensor != 0x08) + return -ENODEV; + + info("HDCS-1000/1100 sensor detected"); + + sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1x00.modes; + sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1x00.nmodes; + sd->desc.ctrls = stv06xx_sensor_hdcs1x00.ctrls; + sd->desc.nctrls = stv06xx_sensor_hdcs1x00.nctrls; + + hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); + if (!hdcs) + return -ENOMEM; + + hdcs->array.left = 8; + hdcs->array.top = 8; + hdcs->array.width = HDCS_1X00_DEF_WIDTH; + hdcs->array.height = HDCS_1X00_DEF_HEIGHT; + hdcs->array.border = 4; + + hdcs->exp.cto = 4; + hdcs->exp.cpo = 2; + hdcs->exp.rs = 186; + hdcs->exp.er = 100; + + /* + * Frame rate on HDCS-1000 0x46D:0x840 depends on PSMP: + * 4 = doesn't work at all + * 5 = 7.8 fps, + * 6 = 6.9 fps, + * 8 = 6.3 fps, + * 10 = 5.5 fps, + * 15 = 4.4 fps, + * 31 = 2.8 fps + * + * Frame rate on HDCS-1000 0x46D:0x870 depends on PSMP: + * 15 = doesn't work at all + * 18 = doesn't work at all + * 19 = 7.3 fps + * 20 = 7.4 fps + * 21 = 7.4 fps + * 22 = 7.4 fps + * 24 = 6.3 fps + * 30 = 5.4 fps + */ + hdcs->psmp = IS_870(sd) ? 20 : 5; + + sd->sensor_priv = hdcs; + + return 0; +} + +static int hdcs_probe_1020(struct sd *sd) +{ + struct hdcs *hdcs; + u16 sensor; + int ret; + + ret = stv06xx_read_sensor(sd, HDCS_IDENT, &sensor); + if (ret < 0 || sensor != 0x10) + return -ENODEV; + + info("HDCS-1020 sensor detected"); + + sd->gspca_dev.cam.cam_mode = stv06xx_sensor_hdcs1020.modes; + sd->gspca_dev.cam.nmodes = stv06xx_sensor_hdcs1020.nmodes; + sd->desc.ctrls = stv06xx_sensor_hdcs1020.ctrls; + sd->desc.nctrls = stv06xx_sensor_hdcs1020.nctrls; + + hdcs = kmalloc(sizeof(struct hdcs), GFP_KERNEL); + if (!hdcs) + return -ENOMEM; + + /* + * From Andrey's test image: looks like HDCS-1020 upper-left + * visible pixel is at 24,8 (y maybe even smaller?) and lower-right + * visible pixel at 375,299 (x maybe even larger?) + */ + hdcs->array.left = 24; + hdcs->array.top = 4; + hdcs->array.width = HDCS_1020_DEF_WIDTH; + hdcs->array.height = 304; + hdcs->array.border = 4; + + hdcs->psmp = 6; + + hdcs->exp.cto = 3; + hdcs->exp.cpo = 3; + hdcs->exp.rs = 155; + hdcs->exp.er = 96; + + sd->sensor_priv = hdcs; + + return 0; +} + +static int hdcs_start(struct sd *sd) +{ + PDEBUG(D_STREAM, "Starting stream"); + + return hdcs_set_state(sd, HDCS_STATE_RUN); +} + +static int hdcs_stop(struct sd *sd) +{ + PDEBUG(D_STREAM, "Halting stream"); + + 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; + int i, err = 0; + + /* Set the STV0602AA in STV0600 emulation mode */ + if (IS_870(sd)) + stv06xx_write_bridge(sd, STV_STV0600_EMULATION, 1); + + /* Execute the bridge init */ + for (i = 0; i < ARRAY_SIZE(stv_bridge_init) && !err; i++) { + err = stv06xx_write_bridge(sd, stv_bridge_init[i][0], + stv_bridge_init[i][1]); + } + if (err < 0) + return err; + + /* sensor soft reset */ + hdcs_reset(sd); + + /* Execute the sensor init */ + for (i = 0; i < ARRAY_SIZE(stv_sensor_init) && !err; i++) { + err = stv06xx_write_sensor(sd, stv_sensor_init[i][0], + stv_sensor_init[i][1]); + } + if (err < 0) + return err; + + /* Enable continous frame capture, bit 2: stop when frame complete */ + err = stv06xx_write_sensor(sd, HDCS_REG_CONFIG(sd), BIT(3)); + if (err < 0) + return err; + + /* Set PGA sample duration + (was 0x7E for IS_870, but caused slow framerate with HDCS-1020) */ + if (IS_1020(sd)) + err = stv06xx_write_sensor(sd, HDCS_TCTRL, + (HDCS_ADC_START_SIG_DUR << 6) | hdcs->psmp); + else + err = stv06xx_write_sensor(sd, HDCS_TCTRL, + (HDCS_ADC_START_SIG_DUR << 5) | hdcs->psmp); + if (err < 0) + return err; + + err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN, HDCS_DEFAULT_GAIN, + HDCS_DEFAULT_GAIN); + if (err < 0) + return err; + + err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE); + if (err < 0) + return err; + + err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height); + return err; +} + +static int hdcs_dump(struct sd *sd) +{ + u16 reg, val; + + info("Dumping sensor registers:"); + + for (reg = HDCS_IDENT; reg <= HDCS_ROWEXPH; reg++) { + stv06xx_read_sensor(sd, reg, &val); + info("reg 0x%02x = 0x%02x", reg, val); + } + return 0; +} diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h new file mode 100644 index 000000000..9c7279a4c --- /dev/null +++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * Copyright (c) 2008 Chia-I Wu + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#ifndef STV06XX_HDCS_H_ +#define STV06XX_HDCS_H_ + +#include "stv06xx_sensor.h" + +#define HDCS_REG_CONFIG(sd) (IS_1020(sd) ? HDCS20_CONFIG : HDCS00_CONFIG) +#define HDCS_REG_CONTROL(sd) (IS_1020(sd) ? HDCS20_CONTROL : HDCS00_CONTROL) + +#define HDCS_1X00_DEF_WIDTH 360 +#define HDCS_1X00_DEF_HEIGHT 296 + +#define HDCS_1020_DEF_WIDTH 352 +#define HDCS_1020_DEF_HEIGHT 292 + +#define HDCS_1020_BOTTOM_Y_SKIP 4 + +#define HDCS_CLK_FREQ_MHZ 25 + +#define HDCS_ADC_START_SIG_DUR 3 + +/* LSB bit of I2C or register address signifies write (0) or read (1) */ +/* I2C Registers common for both HDCS-1000/1100 and HDCS-1020 */ +/* Identifications Register */ +#define HDCS_IDENT (0x00 << 1) +/* Status Register */ +#define HDCS_STATUS (0x01 << 1) +/* Interrupt Mask Register */ +#define HDCS_IMASK (0x02 << 1) +/* Pad Control Register */ +#define HDCS_PCTRL (0x03 << 1) +/* Pad Drive Control Register */ +#define HDCS_PDRV (0x04 << 1) +/* Interface Control Register */ +#define HDCS_ICTRL (0x05 << 1) +/* Interface Timing Register */ +#define HDCS_ITMG (0x06 << 1) +/* Baud Fraction Register */ +#define HDCS_BFRAC (0x07 << 1) +/* Baud Rate Register */ +#define HDCS_BRATE (0x08 << 1) +/* ADC Control Register */ +#define HDCS_ADCCTRL (0x09 << 1) +/* First Window Row Register */ +#define HDCS_FWROW (0x0a << 1) +/* First Window Column Register */ +#define HDCS_FWCOL (0x0b << 1) +/* Last Window Row Register */ +#define HDCS_LWROW (0x0c << 1) +/* Last Window Column Register */ +#define HDCS_LWCOL (0x0d << 1) +/* Timing Control Register */ +#define HDCS_TCTRL (0x0e << 1) +/* PGA Gain Register: Even Row, Even Column */ +#define HDCS_ERECPGA (0x0f << 1) +/* PGA Gain Register: Even Row, Odd Column */ +#define HDCS_EROCPGA (0x10 << 1) +/* PGA Gain Register: Odd Row, Even Column */ +#define HDCS_ORECPGA (0x11 << 1) +/* PGA Gain Register: Odd Row, Odd Column */ +#define HDCS_OROCPGA (0x12 << 1) +/* Row Exposure Low Register */ +#define HDCS_ROWEXPL (0x13 << 1) +/* Row Exposure High Register */ +#define HDCS_ROWEXPH (0x14 << 1) + +/* I2C Registers only for HDCS-1000/1100 */ +/* Sub-Row Exposure Low Register */ +#define HDCS00_SROWEXPL (0x15 << 1) +/* Sub-Row Exposure High Register */ +#define HDCS00_SROWEXPH (0x16 << 1) +/* Configuration Register */ +#define HDCS00_CONFIG (0x17 << 1) +/* Control Register */ +#define HDCS00_CONTROL (0x18 << 1) + +/* I2C Registers only for HDCS-1020 */ +/* Sub-Row Exposure Register */ +#define HDCS20_SROWEXP (0x15 << 1) +/* Error Control Register */ +#define HDCS20_ERROR (0x16 << 1) +/* Interface Timing 2 Register */ +#define HDCS20_ITMG2 (0x17 << 1) +/* Interface Control 2 Register */ +#define HDCS20_ICTRL2 (0x18 << 1) +/* Horizontal Blank Register */ +#define HDCS20_HBLANK (0x19 << 1) +/* Vertical Blank Register */ +#define HDCS20_VBLANK (0x1a << 1) +/* Configuration Register */ +#define HDCS20_CONFIG (0x1b << 1) +/* Control Register */ +#define HDCS20_CONTROL (0x1c << 1) + +#define HDCS_RUN_ENABLE (1 << 2) +#define HDCS_SLEEP_MODE (1 << 1) + +#define HDCS_DEFAULT_EXPOSURE 5000 +#define HDCS_DEFAULT_GAIN 128 + +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_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", + .i2c_flush = 0, + .i2c_addr = (0x55 << 1), + .i2c_len = 1, + + .init = hdcs_init, + .probe = hdcs_probe_1x00, + .start = hdcs_start, + .stop = hdcs_stop, + .disconnect = hdcs_disconnect, + .dump = hdcs_dump, + + .nctrls = 2, + .ctrls = { + { + { + .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 + } + }, + + .nmodes = 1, + .modes = { + { + HDCS_1X00_DEF_WIDTH, + HDCS_1X00_DEF_HEIGHT, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + HDCS_1X00_DEF_WIDTH * HDCS_1X00_DEF_HEIGHT, + .bytesperline = HDCS_1X00_DEF_WIDTH, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + } + } +}; + +const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = { + .name = "HDCS-1020", + .i2c_flush = 0, + .i2c_addr = (0x55 << 1), + .i2c_len = 1, + + .nctrls = 0, + .ctrls = {}, + + .init = hdcs_init, + .probe = hdcs_probe_1020, + .start = hdcs_start, + .stop = hdcs_stop, + .dump = hdcs_dump, + + .nmodes = 1, + .modes = { + { + HDCS_1020_DEF_WIDTH, + HDCS_1020_DEF_HEIGHT, + V4L2_PIX_FMT_SBGGR8, + V4L2_FIELD_NONE, + .sizeimage = + HDCS_1020_DEF_WIDTH * HDCS_1020_DEF_HEIGHT, + .bytesperline = HDCS_1020_DEF_WIDTH, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 1 + } + } +}; + +static const u16 stv_bridge_init[][2] = { + {STV_ISO_ENABLE, 0}, + {STV_REG23, 0}, + {STV_REG00, 0x1d}, + {STV_REG01, 0xb5}, + {STV_REG02, 0xa8}, + {STV_REG03, 0x95}, + {STV_REG04, 0x07}, + + {STV_SCAN_RATE, 0x20}, + {STV_ISO_SIZE_L, 847}, + {STV_Y_CTRL, 0x01}, + {STV_X_CTRL, 0x0a} +}; + +static const u8 stv_sensor_init[][2] = { + /* Clear status (writing 1 will clear the corresponding status bit) */ + {HDCS_STATUS, BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, + /* Disable all interrupts */ + {HDCS_IMASK, 0x00}, + {HDCS_PCTRL, BIT(6) | BIT(5) | BIT(1) | BIT(0)}, + {HDCS_PDRV, 0x00}, + {HDCS_ICTRL, BIT(5)}, + {HDCS_ITMG, BIT(4) | BIT(1)}, + /* ADC output resolution to 10 bits */ + {HDCS_ADCCTRL, 10} +}; + +#endif diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c new file mode 100644 index 000000000..d0a0f8596 --- /dev/null +++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +/* + * The spec file for the PB-0100 suggests the following for best quality + * images after the sensor has been reset : + * + * PB_ADCGAINL = R60 = 0x03 (3 dec) : sets low reference of ADC + to produce good black level + * PB_PREADCTRL = R32 = 0x1400 (5120 dec) : Enables global gain changes + through R53 + * PB_ADCMINGAIN = R52 = 0x10 (16 dec) : Sets the minimum gain for + auto-exposure + * PB_ADCGLOBALGAIN = R53 = 0x10 (16 dec) : Sets the global gain + * PB_EXPGAIN = R14 = 0x11 (17 dec) : Sets the auto-exposure value + * PB_UPDATEINT = R23 = 0x02 (2 dec) : Sets the speed on + auto-exposure routine + * PB_CFILLIN = R5 = 0x0E (14 dec) : Sets the frame rate + */ + +#include "stv06xx_pb0100.h" + +static int pb0100_probe(struct sd *sd) +{ + u16 sensor; + int i, err; + s32 *sensor_settings; + + err = stv06xx_read_sensor(sd, PB_IDENT, &sensor); + + if (err < 0) + return -ENODEV; + + if ((sensor >> 8) == 0x64) { + sensor_settings = kmalloc( + stv06xx_sensor_pb0100.nctrls * sizeof(s32), + GFP_KERNEL); + if (!sensor_settings) + return -ENOMEM; + + info("Photobit pb0100 sensor detected"); + + sd->gspca_dev.cam.cam_mode = stv06xx_sensor_pb0100.modes; + sd->gspca_dev.cam.nmodes = stv06xx_sensor_pb0100.nmodes; + sd->desc.ctrls = stv06xx_sensor_pb0100.ctrls; + sd->desc.nctrls = stv06xx_sensor_pb0100.nctrls; + for (i = 0; i < stv06xx_sensor_pb0100.nctrls; i++) + sensor_settings[i] = stv06xx_sensor_pb0100. + ctrls[i].qctrl.default_value; + sd->sensor_priv = sensor_settings; + + return 0; + } + + return -ENODEV; +} + +static int pb0100_start(struct sd *sd) +{ + int err; + struct cam *cam = &sd->gspca_dev.cam; + s32 *sensor_settings = sd->sensor_priv; + u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv; + + /* Setup sensor window */ + if (mode & PB0100_CROP_TO_VGA) { + stv06xx_write_sensor(sd, PB_RSTART, 30); + stv06xx_write_sensor(sd, PB_CSTART, 20); + stv06xx_write_sensor(sd, PB_RWSIZE, 240 - 1); + stv06xx_write_sensor(sd, PB_CWSIZE, 320 - 1); + } else { + stv06xx_write_sensor(sd, PB_RSTART, 8); + stv06xx_write_sensor(sd, PB_CSTART, 4); + stv06xx_write_sensor(sd, PB_RWSIZE, 288 - 1); + stv06xx_write_sensor(sd, PB_CWSIZE, 352 - 1); + } + + if (mode & PB0100_SUBSAMPLE) { + stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); /* Wrong, FIXME */ + stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); + + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); + } else { + stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); + stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); + /* larger -> slower */ + 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); + + return (err < 0) ? err : 0; +} + +static int pb0100_stop(struct sd *sd) +{ + int err; + + err = stv06xx_write_sensor(sd, PB_ABORTFRAME, 1); + + if (err < 0) + goto out; + + /* Set bit 1 to zero */ + err = stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)); + + PDEBUG(D_STREAM, "Halting stream"); +out: + return (err < 0) ? err : 0; +} + +/* 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, + add this once the init has been converted to proper tables */ +static int pb0100_init(struct sd *sd) +{ + stv06xx_write_bridge(sd, STV_REG00, 1); + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0); + + /* Reset sensor */ + stv06xx_write_sensor(sd, PB_RESET, 1); + stv06xx_write_sensor(sd, PB_RESET, 0); + + /* Disable chip */ + stv06xx_write_sensor(sd, PB_CONTROL, BIT(5)|BIT(3)); + + /* Gain stuff...*/ + stv06xx_write_sensor(sd, PB_PREADCTRL, BIT(12)|BIT(10)|BIT(6)); + stv06xx_write_sensor(sd, PB_ADCGLOBALGAIN, 12); + + /* Set up auto-exposure */ + /* ADC VREF_HI new setting for a transition + from the Expose1 to the Expose2 setting */ + stv06xx_write_sensor(sd, PB_R28, 12); + /* gain max for autoexposure */ + stv06xx_write_sensor(sd, PB_ADCMAXGAIN, 180); + /* gain min for autoexposure */ + stv06xx_write_sensor(sd, PB_ADCMINGAIN, 12); + /* Maximum frame integration time (programmed into R8) + allowed for auto-exposure routine */ + stv06xx_write_sensor(sd, PB_R54, 3); + /* Minimum frame integration time (programmed into R8) + allowed for auto-exposure routine */ + stv06xx_write_sensor(sd, PB_R55, 0); + stv06xx_write_sensor(sd, PB_UPDATEINT, 1); + /* R15 Expose0 (maximum that auto-exposure may use) */ + stv06xx_write_sensor(sd, PB_R15, 800); + /* R17 Expose2 (minimum that auto-exposure may use) */ + stv06xx_write_sensor(sd, PB_R17, 10); + + stv06xx_write_sensor(sd, PB_EXPGAIN, 0); + + /* 0x14 */ + stv06xx_write_sensor(sd, PB_VOFFSET, 0); + /* 0x0D */ + stv06xx_write_sensor(sd, PB_ADCGAINH, 11); + /* Set black level (important!) */ + stv06xx_write_sensor(sd, PB_ADCGAINL, 0); + + /* ??? */ + stv06xx_write_bridge(sd, STV_REG00, 0x11); + stv06xx_write_bridge(sd, STV_REG03, 0x45); + stv06xx_write_bridge(sd, STV_REG04, 0x07); + + /* ISO-Size (0x27b: 635... why? - HDCS uses 847) */ + stv06xx_write_bridge(sd, STV_ISO_SIZE_L, 847); + + /* Scan/timing for the sensor */ + stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1)); + stv06xx_write_sensor(sd, PB_CFILLIN, 14); + stv06xx_write_sensor(sd, PB_VBL, 0); + stv06xx_write_sensor(sd, PB_FINTTIME, 0); + stv06xx_write_sensor(sd, PB_RINTTIME, 123); + + stv06xx_write_bridge(sd, STV_REG01, 0xc2); + stv06xx_write_bridge(sd, STV_REG02, 0xb0); + return 0; +} + +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; + + 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]); + if (!err) + err = pb0100_set_blue_balance(gspca_dev, + sensor_settings[BLUE_BALANCE_IDX]); + + 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; + + if (sensor_settings[AUTOGAIN_IDX]) + return -EBUSY; + + sensor_settings[RED_BALANCE_IDX] = val; + val += sensor_settings[GAIN_IDX]; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + + err = stv06xx_write_sensor(sd, PB_RGAIN, val); + PDEBUG(D_V4L2, "Set red gain to %d, status: %d", val, err); + + 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; + + if (sensor_settings[AUTOGAIN_IDX]) + return -EBUSY; + + sensor_settings[BLUE_BALANCE_IDX] = val; + val += sensor_settings[GAIN_IDX]; + if (val < 0) + val = 0; + else if (val > 255) + val = 255; + + err = stv06xx_write_sensor(sd, PB_BGAIN, val); + PDEBUG(D_V4L2, "Set blue gain to %d, status: %d", val, err); + + 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; + + 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; + + sensor_settings[AUTOGAIN_IDX] = val; + if (sensor_settings[AUTOGAIN_IDX]) { + if (sensor_settings[NATURAL_IDX]) + val = BIT(6)|BIT(4)|BIT(0); + else + val = BIT(4)|BIT(0); + } else + val = 0; + + 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); + + 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 */ + totalpixels = gspca_dev->width * gspca_dev->height; + totalpixels = totalpixels/(8*8) + totalpixels/(64*64); + + brightpixels = (totalpixels * val) >> 8; + darkpixels = totalpixels - brightpixels; + err = stv06xx_write_sensor(sd, PB_R21, brightpixels); + if (!err) + err = stv06xx_write_sensor(sd, PB_R22, darkpixels); + + PDEBUG(D_V4L2, "Set autogain target to %d, status: %d", val, err); + + 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/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h new file mode 100644 index 000000000..4b47270aa --- /dev/null +++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h @@ -0,0 +1,297 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#ifndef STV06XX_PB0100_H_ +#define STV06XX_PB0100_H_ + +#include "stv06xx_sensor.h" + +/* mode priv field flags */ +#define PB0100_CROP_TO_VGA 0x01 +#define PB0100_SUBSAMPLE 0x02 + +/* I2C Registers */ +#define PB_IDENT 0x00 /* Chip Version */ +#define PB_RSTART 0x01 /* Row Window Start */ +#define PB_CSTART 0x02 /* Column Window Start */ +#define PB_RWSIZE 0x03 /* Row Window Size */ +#define PB_CWSIZE 0x04 /* Column Window Size */ +#define PB_CFILLIN 0x05 /* Column Fill-In */ +#define PB_VBL 0x06 /* Vertical Blank Count */ +#define PB_CONTROL 0x07 /* Control Mode */ +#define PB_FINTTIME 0x08 /* Integration Time/Frame Unit Count */ +#define PB_RINTTIME 0x09 /* Integration Time/Row Unit Count */ +#define PB_ROWSPEED 0x0a /* Row Speed Control */ +#define PB_ABORTFRAME 0x0b /* Abort Frame */ +#define PB_R12 0x0c /* Reserved */ +#define PB_RESET 0x0d /* Reset */ +#define PB_EXPGAIN 0x0e /* Exposure Gain Command */ +#define PB_R15 0x0f /* Expose0 */ +#define PB_R16 0x10 /* Expose1 */ +#define PB_R17 0x11 /* Expose2 */ +#define PB_R18 0x12 /* Low0_DAC */ +#define PB_R19 0x13 /* Low1_DAC */ +#define PB_R20 0x14 /* Low2_DAC */ +#define PB_R21 0x15 /* Threshold11 */ +#define PB_R22 0x16 /* Threshold0x */ +#define PB_UPDATEINT 0x17 /* Update Interval */ +#define PB_R24 0x18 /* High_DAC */ +#define PB_R25 0x19 /* Trans0H */ +#define PB_R26 0x1a /* Trans1L */ +#define PB_R27 0x1b /* Trans1H */ +#define PB_R28 0x1c /* Trans2L */ +#define PB_R29 0x1d /* Reserved */ +#define PB_R30 0x1e /* Reserved */ +#define PB_R31 0x1f /* Wait to Read */ +#define PB_PREADCTRL 0x20 /* Pixel Read Control Mode */ +#define PB_R33 0x21 /* IREF_VLN */ +#define PB_R34 0x22 /* IREF_VLP */ +#define PB_R35 0x23 /* IREF_VLN_INTEG */ +#define PB_R36 0x24 /* IREF_MASTER */ +#define PB_R37 0x25 /* IDACP */ +#define PB_R38 0x26 /* IDACN */ +#define PB_R39 0x27 /* DAC_Control_Reg */ +#define PB_R40 0x28 /* VCL */ +#define PB_R41 0x29 /* IREF_VLN_ADCIN */ +#define PB_R42 0x2a /* Reserved */ +#define PB_G1GAIN 0x2b /* Green 1 Gain */ +#define PB_BGAIN 0x2c /* Blue Gain */ +#define PB_RGAIN 0x2d /* Red Gain */ +#define PB_G2GAIN 0x2e /* Green 2 Gain */ +#define PB_R47 0x2f /* Dark Row Address */ +#define PB_R48 0x30 /* Dark Row Options */ +#define PB_R49 0x31 /* Reserved */ +#define PB_R50 0x32 /* Image Test Data */ +#define PB_ADCMAXGAIN 0x33 /* Maximum Gain */ +#define PB_ADCMINGAIN 0x34 /* Minimum Gain */ +#define PB_ADCGLOBALGAIN 0x35 /* Global Gain */ +#define PB_R54 0x36 /* Maximum Frame */ +#define PB_R55 0x37 /* Minimum Frame */ +#define PB_R56 0x38 /* Reserved */ +#define PB_VOFFSET 0x39 /* VOFFSET */ +#define PB_R58 0x3a /* Snap-Shot Sequence Trigger */ +#define PB_ADCGAINH 0x3b /* VREF_HI */ +#define PB_ADCGAINL 0x3c /* VREF_LO */ +#define PB_R61 0x3d /* Reserved */ +#define PB_R62 0x3e /* Reserved */ +#define PB_R63 0x3f /* Reserved */ +#define PB_R64 0x40 /* Red/Blue Gain */ +#define PB_R65 0x41 /* Green 2/Green 1 Gain */ +#define PB_R66 0x42 /* VREF_HI/LO */ +#define PB_R67 0x43 /* Integration Time/Row Unit Count */ +#define PB_R240 0xf0 /* ADC Test */ +#define PB_R241 0xf1 /* Chip Enable */ +#define PB_R242 0xf2 /* Reserved */ + +static int pb0100_probe(struct sd *sd); +static int pb0100_start(struct sd *sd); +static int pb0100_init(struct sd *sd); +static int pb0100_stop(struct sd *sd); +static int pb0100_dump(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", + .i2c_flush = 1, + .i2c_addr = 0xba, + .i2c_len = 2, + + .nctrls = 7, + .ctrls = { +#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 + }, + }, + + .init = pb0100_init, + .probe = pb0100_probe, + .start = pb0100_start, + .stop = pb0100_stop, + .dump = pb0100_dump, + + .nmodes = 2, + .modes = { +/* low res / subsample modes disabled as they are only half res horizontal, + halving the vertical resolution does not seem to work */ +#if 0 + { + 160, + 120, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = 160 * 120 * 2, + .bytesperline = 160, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = PB0100_CROP_TO_VGA | PB0100_SUBSAMPLE + }, + { + 176, + 144, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = 176 * 144 * 2, + .bytesperline = 176, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = PB0100_SUBSAMPLE + }, +#endif + { + 320, + 240, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = 320 * 240, + .bytesperline = 320, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = PB0100_CROP_TO_VGA + }, + { + 352, + 288, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = 352 * 288, + .bytesperline = 352, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + }, + } +}; + +#endif diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h new file mode 100644 index 000000000..c726dacef --- /dev/null +++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#ifndef STV06XX_SENSOR_H_ +#define STV06XX_SENSOR_H_ + +#include "stv06xx.h" + +#define IS_850(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x850) +#define IS_870(sd) ((sd)->gspca_dev.dev->descriptor.idProduct == 0x870) +#define IS_1020(sd) ((sd)->sensor == &stv06xx_sensor_hdcs1020) + +extern const struct stv06xx_sensor stv06xx_sensor_vv6410; +extern const struct stv06xx_sensor stv06xx_sensor_hdcs1x00; +extern const struct stv06xx_sensor stv06xx_sensor_hdcs1020; +extern const struct stv06xx_sensor stv06xx_sensor_pb0100; + +#define STV06XX_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10) + +struct stv06xx_sensor { + /* Defines the name of a sensor */ + char name[32]; + + /* Sensor i2c address */ + u8 i2c_addr; + + /* Flush value*/ + u8 i2c_flush; + + /* length of an i2c word */ + u8 i2c_len; + + /* Probes if the sensor is connected */ + int (*probe)(struct sd *sd); + + /* Performs a initialization sequence */ + int (*init)(struct sd *sd); + + /* Executed at device disconnect */ + void (*disconnect)(struct sd *sd); + + /* Reads a sensor register */ + int (*read_sensor)(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + + /* Writes to a sensor register */ + int (*write_sensor)(struct sd *sd, const u8 address, + u8 *i2c_data, const u8 len); + + /* Instructs the sensor to start streaming */ + int (*start)(struct sd *sd); + + /* Instructs the sensor to stop streaming */ + int (*stop)(struct sd *sd); + + /* Instructs the sensor to dump all its contents */ + int (*dump)(struct sd *sd); + + int nctrls; + struct ctrl ctrls[STV06XX_MAX_CTRLS]; + + char nmodes; + struct v4l2_pix_format modes[]; +}; + +#endif diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c new file mode 100644 index 000000000..1ca91f2a6 --- /dev/null +++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c @@ -0,0 +1,251 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#include "stv06xx_vv6410.h" + +static int vv6410_probe(struct sd *sd) +{ + u16 data; + int err; + + err = stv06xx_read_sensor(sd, VV6410_DEVICEH, &data); + + if (err < 0) + return -ENODEV; + + if (data == 0x19) { + info("vv6410 sensor detected"); + + sd->gspca_dev.cam.cam_mode = stv06xx_sensor_vv6410.modes; + sd->gspca_dev.cam.nmodes = stv06xx_sensor_vv6410.nmodes; + sd->desc.ctrls = stv06xx_sensor_vv6410.ctrls; + sd->desc.nctrls = stv06xx_sensor_vv6410.nctrls; + return 0; + } + + return -ENODEV; +} + +static int vv6410_init(struct sd *sd) +{ + int err = 0, i; + + for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) { + /* if NULL then len contains single value */ + if (stv_bridge_init[i].data == NULL) { + err = stv06xx_write_bridge(sd, + stv_bridge_init[i].start, + stv_bridge_init[i].len); + } else { + int j; + for (j = 0; j < stv_bridge_init[i].len; j++) + err = stv06xx_write_bridge(sd, + stv_bridge_init[i].start + j, + stv_bridge_init[i].data[j]); + } + } + + if (err < 0) + return err; + + err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init, + ARRAY_SIZE(vv6410_sensor_init)); + + return (err < 0) ? err : 0; +} + +static int vv6410_start(struct sd *sd) +{ + int err; + struct cam *cam = &sd->gspca_dev.cam; + u32 priv = cam->cam_mode[sd->gspca_dev.curr_mode].priv; + + if (priv & VV6410_CROP_TO_QVGA) { + PDEBUG(D_CONF, "Cropping to QVGA"); + stv06xx_write_sensor(sd, VV6410_XENDH, 320 - 1); + stv06xx_write_sensor(sd, VV6410_YENDH, 240 - 1); + } else { + stv06xx_write_sensor(sd, VV6410_XENDH, 360 - 1); + stv06xx_write_sensor(sd, VV6410_YENDH, 294 - 1); + } + + if (priv & VV6410_SUBSAMPLE) { + PDEBUG(D_CONF, "Enabling subsampling"); + stv06xx_write_bridge(sd, STV_Y_CTRL, 0x02); + stv06xx_write_bridge(sd, STV_X_CTRL, 0x06); + + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x10); + } else { + stv06xx_write_bridge(sd, STV_Y_CTRL, 0x01); + stv06xx_write_bridge(sd, STV_X_CTRL, 0x0a); + + stv06xx_write_bridge(sd, STV_SCAN_RATE, 0x20); + } + + /* Turn on LED */ + err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_ON); + if (err < 0) + return err; + + err = stv06xx_write_sensor(sd, VV6410_SETUP0, 0); + if (err < 0) + return err; + + PDEBUG(D_STREAM, "Starting stream"); + + return 0; +} + +static int vv6410_stop(struct sd *sd) +{ + int err; + + /* Turn off LED */ + err = stv06xx_write_bridge(sd, STV_LED_CTRL, LED_OFF); + if (err < 0) + return err; + + err = stv06xx_write_sensor(sd, VV6410_SETUP0, VV6410_LOW_POWER_MODE); + if (err < 0) + return err; + + PDEBUG(D_STREAM, "Halting stream"); + + return (err < 0) ? err : 0; +} + +static int vv6410_dump(struct sd *sd) +{ + u8 i; + int err = 0; + + info("Dumping all vv6410 sensor registers"); + for (i = 0; i < 0xff && !err; i++) { + u16 data; + err = stv06xx_read_sensor(sd, i, &data); + info("Register 0x%x contained 0x%x", i, data); + } + return (err < 0) ? err : 0; +} + +static int vv6410_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u16 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); + + *val = (i2c_data & VV6410_HFLIP) ? 1 : 0; + + PDEBUG(D_V4L2, "Read horizontal flip %d", *val); + + return (err < 0) ? err : 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; + err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); + if (err < 0) + return err; + + if (val) + i2c_data |= VV6410_HFLIP; + else + i2c_data &= ~VV6410_HFLIP; + + PDEBUG(D_V4L2, "Set horizontal flip to %d", val); + err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); + + return (err < 0) ? err : 0; +} + +static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u16 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); + + *val = (i2c_data & VV6410_VFLIP) ? 1 : 0; + + PDEBUG(D_V4L2, "Read vertical flip %d", *val); + + return (err < 0) ? err : 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; + err = stv06xx_read_sensor(sd, VV6410_DATAFORMAT, &i2c_data); + if (err < 0) + return err; + + if (val) + i2c_data |= VV6410_VFLIP; + else + i2c_data &= ~VV6410_VFLIP; + + PDEBUG(D_V4L2, "Set vertical flip to %d", val); + err = stv06xx_write_sensor(sd, VV6410_DATAFORMAT, i2c_data); + + return (err < 0) ? err : 0; +} + +static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val) +{ + int err; + u16 i2c_data; + struct sd *sd = (struct sd *) gspca_dev; + + err = stv06xx_read_sensor(sd, VV6410_ANALOGGAIN, &i2c_data); + + *val = i2c_data & 0xf; + + PDEBUG(D_V4L2, "Read analog gain %d", *val); + + return (err < 0) ? err : 0; +} + +static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val) +{ + int err; + struct sd *sd = (struct sd *) gspca_dev; + + PDEBUG(D_V4L2, "Set analog gain to %d", val); + err = stv06xx_write_sensor(sd, VV6410_ANALOGGAIN, 0xf0 | (val & 0xf)); + + return (err < 0) ? err : 0; +} diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h new file mode 100644 index 000000000..3ff8c4ea3 --- /dev/null +++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher + * Mark Cave-Ayland, Carlo E Prelz, Dick Streefland + * Copyright (c) 2002, 2003 Tuukka Toivonen + * Copyright (c) 2008 Erik Andrén + * + * 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 + * + * P/N 861037: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0010: Sensor HDCS1000 ASIC STV0600 + * P/N 861050-0020: Sensor Photobit PB100 ASIC STV0600-1 - QuickCam Express + * P/N 861055: Sensor ST VV6410 ASIC STV0610 - LEGO cam + * P/N 861075-0040: Sensor HDCS1000 ASIC + * P/N 961179-0700: Sensor ST VV6410 ASIC STV0602 - Dexxa WebCam USB + * P/N 861040-0000: Sensor ST VV6410 ASIC STV0610 - QuickCam Web + */ + +#ifndef STV06XX_VV6410_H_ +#define STV06XX_VV6410_H_ + +#include "stv06xx_sensor.h" + +#define VV6410_COLS 416 +#define VV6410_ROWS 320 + +/* Status registers */ +/* Chip identification number including revision indicator */ +#define VV6410_DEVICEH 0x00 +#define VV6410_DEVICEL 0x01 + +/* User can determine whether timed I2C data + has been consumed by interrogating flag states */ +#define VV6410_STATUS0 0x02 + +/* Current line counter value */ +#define VV6410_LINECOUNTH 0x03 +#define VV6410_LINECOUNTL 0x04 + +/* End x coordinate of image size */ +#define VV6410_XENDH 0x05 +#define VV6410_XENDL 0x06 + +/* End y coordinate of image size */ +#define VV6410_YENDH 0x07 +#define VV6410_YENDL 0x08 + +/* This is the average pixel value returned from the + dark line offset cancellation algorithm */ +#define VV6410_DARKAVGH 0x09 +#define VV6410_DARKAVGL 0x0a + +/* This is the average pixel value returned from the + black line offset cancellation algorithm */ +#define VV6410_BLACKAVGH 0x0b +#define VV6410_BLACKAVGL 0x0c + +/* Flags to indicate whether the x or y image coordinates have been clipped */ +#define VV6410_STATUS1 0x0d + +/* Setup registers */ + +/* Low-power/sleep modes & video timing */ +#define VV6410_SETUP0 0x10 + +/* Various parameters */ +#define VV6410_SETUP1 0x11 + +/* Contains pixel counter reset value used by external sync */ +#define VV6410_SYNCVALUE 0x12 + +/* Frame grabbing modes (FST, LST and QCK) */ +#define VV6410_FGMODES 0x14 + +/* FST and QCK mapping modes. */ +#define VV6410_PINMAPPING 0x15 + +/* Data resolution */ +#define VV6410_DATAFORMAT 0x16 + +/* Output coding formats */ +#define VV6410_OPFORMAT 0x17 + +/* Various mode select bits */ +#define VV6410_MODESELECT 0x18 + +/* Exposure registers */ +/* Fine exposure. */ +#define VV6410_FINEH 0x20 +#define VV6410_FINEL 0x21 + +/* Coarse exposure */ +#define VV6410_COARSEH 0x22 +#define VV6410_COARSEL 0x23 + +/* Analog gain setting */ +#define VV6410_ANALOGGAIN 0x24 + +/* Clock division */ +#define VV6410_CLKDIV 0x25 + +/* Dark line offset cancellation value */ +#define VV6410_DARKOFFSETH 0x2c +#define VV6410_DARKOFFSETL 0x2d + +/* Dark line offset cancellation enable */ +#define VV6410_DARKOFFSETSETUP 0x2e + +/* Video timing registers */ +/* Line Length (Pixel Clocks) */ +#define VV6410_LINELENGTHH 0x52 +#define VV6410_LINELENGTHL 0x53 + +/* X-co-ordinate of top left corner of region of interest (x-offset) */ +#define VV6410_XOFFSETH 0x57 +#define VV6410_XOFFSETL 0x58 + +/* Y-coordinate of top left corner of region of interest (y-offset) */ +#define VV6410_YOFFSETH 0x59 +#define VV6410_YOFFSETL 0x5a + +/* Field length (Lines) */ +#define VV6410_FIELDLENGTHH 0x61 +#define VV6410_FIELDLENGTHL 0x62 + +/* System registers */ +/* Black offset cancellation default value */ +#define VV6410_BLACKOFFSETH 0x70 +#define VV6410_BLACKOFFSETL 0x71 + +/* Black offset cancellation setup */ +#define VV6410_BLACKOFFSETSETUP 0x72 + +/* Analog Control Register 0 */ +#define VV6410_CR0 0x75 + +/* Analog Control Register 1 */ +#define VV6410_CR1 0x76 + +/* ADC Setup Register */ +#define VV6410_AS0 0x77 + +/* Analog Test Register */ +#define VV6410_AT0 0x78 + +/* Audio Amplifier Setup Register */ +#define VV6410_AT1 0x79 + +#define VV6410_HFLIP (1 << 3) +#define VV6410_VFLIP (1 << 4) + +#define VV6410_LOW_POWER_MODE (1 << 0) +#define VV6410_SOFT_RESET (1 << 2) +#define VV6410_PAL_25_FPS (0 << 3) + +#define VV6410_CLK_DIV_2 (1 << 1) + +#define VV6410_FINE_EXPOSURE 320 +#define VV6410_COARSE_EXPOSURE 192 +#define VV6410_DEFAULT_GAIN 5 + +#define VV6410_SUBSAMPLE 0x01 +#define VV6410_CROP_TO_QVGA 0x02 + +static int vv6410_probe(struct sd *sd); +static int vv6410_start(struct sd *sd); +static int vv6410_init(struct sd *sd); +static int vv6410_stop(struct sd *sd); +static int vv6410_dump(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); + +const struct stv06xx_sensor stv06xx_sensor_vv6410 = { + .name = "ST VV6410", + .i2c_flush = 5, + .i2c_addr = 0x20, + .i2c_len = 1, + .init = vv6410_init, + .probe = vv6410_probe, + .start = vv6410_start, + .stop = vv6410_stop, + .dump = vv6410_dump, + + .nctrls = 3, + .ctrls = { + { + { + .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 + }, { + { + .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 + }, { + { + .id = V4L2_CID_GAIN, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "analog gain", + .minimum = 0, + .maximum = 15, + .step = 1, + .default_value = 0 + }, + .set = vv6410_set_analog_gain, + .get = vv6410_get_analog_gain + } + }, + + .nmodes = 1, + .modes = { + { + 356, + 292, + V4L2_PIX_FMT_SGRBG8, + V4L2_FIELD_NONE, + .sizeimage = + 356 * 292, + .bytesperline = 356, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = 0 + } + } +}; + +/* If NULL, only single value to write, stored in len */ +struct stv_init { + const u8 *data; + u16 start; + u8 len; +}; + +static const u8 x1500[] = { /* 0x1500 - 0x150f */ + 0x0b, 0xa7, 0xb7, 0x00, 0x00 +}; + +static const u8 x1536[] = { /* 0x1536 - 0x153b */ + 0x02, 0x00, 0x60, 0x01, 0x20, 0x01 +}; + +static const u8 x15c1[] = { /* 0x15c1 - 0x15c2 */ + 0xff, 0x03 /* Output word 0x03ff = 1023 (ISO size) */ +}; + +static const struct stv_init stv_bridge_init[] = { + /* This reg is written twice. Some kind of reset? */ + {NULL, 0x1620, 0x80}, + {NULL, 0x1620, 0x00}, + {NULL, 0x1423, 0x04}, + {x1500, 0x1500, ARRAY_SIZE(x1500)}, + {x1536, 0x1536, ARRAY_SIZE(x1536)}, + {x15c1, 0x15c1, ARRAY_SIZE(x15c1)} +}; + +static const u8 vv6410_sensor_init[][2] = { + /* Setup registers */ + {VV6410_SETUP0, VV6410_SOFT_RESET}, + {VV6410_SETUP0, VV6410_LOW_POWER_MODE}, + /* Use shuffled read-out mode */ + {VV6410_SETUP1, BIT(6)}, + /* All modes to 1 */ + {VV6410_FGMODES, BIT(6) | BIT(4) | BIT(2) | BIT(0)}, + {VV6410_PINMAPPING, 0x00}, + /* Pre-clock generator divide off */ + {VV6410_DATAFORMAT, BIT(7) | BIT(0)}, + + /* Exposure registers */ + {VV6410_FINEH, VV6410_FINE_EXPOSURE >> 8}, + {VV6410_FINEL, VV6410_FINE_EXPOSURE & 0xff}, + {VV6410_COARSEH, VV6410_COARSE_EXPOSURE >> 8}, + {VV6410_COARSEL, VV6410_COARSE_EXPOSURE & 0xff}, + {VV6410_ANALOGGAIN, 0xf0 | VV6410_DEFAULT_GAIN}, + {VV6410_CLKDIV, VV6410_CLK_DIV_2}, + + /* System registers */ + /* Enable voltage doubler */ + {VV6410_AS0, BIT(6) | BIT(4) | BIT(3) | BIT(2) | BIT(1)}, + {VV6410_AT0, 0x00}, + /* Power up audio, differential */ + {VV6410_AT1, BIT(4)|BIT(0)}, +}; + +#endif diff --git a/linux/drivers/media/video/gspca/sunplus.c b/linux/drivers/media/video/gspca/sunplus.c index 3a972ff1c..3692062d0 100644 --- a/linux/drivers/media/video/gspca/sunplus.c +++ b/linux/drivers/media/video/gspca/sunplus.c @@ -123,7 +123,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, @@ -136,7 +136,7 @@ static struct v4l2_pix_format vga_mode[] = { .priv = 1}, }; -static struct v4l2_pix_format custom_mode[] = { +static const struct v4l2_pix_format custom_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, @@ -149,7 +149,7 @@ static struct v4l2_pix_format custom_mode[] = { .priv = 1}, }; -static struct v4l2_pix_format vga_mode2[] = { +static const struct v4l2_pix_format vga_mode2[] = { {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 176, .sizeimage = 176 * 144 * 3 / 8 + 590, diff --git a/linux/drivers/media/video/gspca/t613.c b/linux/drivers/media/video/gspca/t613.c index d2d6ad9d1..2d032aa0e 100644 --- a/linux/drivers/media/video/gspca/t613.c +++ b/linux/drivers/media/video/gspca/t613.c @@ -233,7 +233,7 @@ static char *effects_control[] = { "Negative", }; -static struct v4l2_pix_format vga_mode_t16[] = { +static const struct v4l2_pix_format vga_mode_t16[] = { {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 160, .sizeimage = 160 * 120 * 4 / 8 + 590, @@ -499,7 +499,7 @@ static void om6802_sensor_init(struct gspca_dev *gspca_dev) reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset); msleep(5); i = 4; - while (--i < 0) { + while (--i > 0) { byte = reg_r(gspca_dev, 0x0060); if (!(byte & 0x01)) break; diff --git a/linux/drivers/media/video/gspca/tv8532.c b/linux/drivers/media/video/gspca/tv8532.c index 4e18f90ba..7d11a0d3e 100644 --- a/linux/drivers/media/video/gspca/tv8532.c +++ b/linux/drivers/media/video/gspca/tv8532.c @@ -73,7 +73,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format sif_mode[] = { +static const struct v4l2_pix_format sif_mode[] = { {176, 144, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE, .bytesperline = 176, .sizeimage = 176 * 144, diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c index f6fae60ae..82dc818f4 100644 --- a/linux/drivers/media/video/gspca/vc032x.c +++ b/linux/drivers/media/video/gspca/vc032x.c @@ -32,44 +32,68 @@ MODULE_LICENSE("GPL"); struct sd { struct gspca_dev gspca_dev; /* !! must be the first item */ - unsigned char autogain; - unsigned char lightfreq; + __u8 hflip; + __u8 vflip; + __u8 lightfreq; + __u8 sharpness; - char qindex; char bridge; #define BRIDGE_VC0321 0 #define BRIDGE_VC0323 1 char sensor; #define SENSOR_HV7131R 0 -#define SENSOR_MI1320 1 -#define SENSOR_MI1310_SOC 2 -#define SENSOR_OV7660 3 -#define SENSOR_OV7670 4 -#define SENSOR_PO3130NC 5 +#define SENSOR_MI0360 1 +#define SENSOR_MI1320 2 +#define SENSOR_MI1310_SOC 3 +#define SENSOR_OV7660 4 +#define SENSOR_OV7670 5 +#define SENSOR_PO1200 6 +#define SENSOR_PO3130NC 7 }; /* V4L2 controls supported by the driver */ -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_setfreq(struct gspca_dev *gspca_dev, __s32 val); static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val); +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val); +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val); static struct ctrl sd_ctrls[] = { +/* next 2 controls work with ov7660 and ov7670 only */ +#define HFLIP_IDX 0 { { - .id = V4L2_CID_AUTOGAIN, + .id = V4L2_CID_HFLIP, .type = V4L2_CTRL_TYPE_BOOLEAN, - .name = "Auto Gain", + .name = "Mirror", .minimum = 0, .maximum = 1, .step = 1, -#define AUTOGAIN_DEF 1 - .default_value = AUTOGAIN_DEF, +#define HFLIP_DEF 0 + .default_value = HFLIP_DEF, }, - .set = sd_setautogain, - .get = sd_getautogain, + .set = sd_sethflip, + .get = sd_gethflip, }, -#define LIGHTFREQ_IDX 1 +#define VFLIP_IDX 1 + { + { + .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, + }, +#define LIGHTFREQ_IDX 2 { { .id = V4L2_CID_POWER_LINE_FREQUENCY, @@ -84,9 +108,25 @@ static struct ctrl sd_ctrls[] = { .set = sd_setfreq, .get = sd_getfreq, }, +/* po1200 only */ +#define SHARPNESS_IDX 3 + { + { + .id = V4L2_CID_SHARPNESS, + .type = V4L2_CTRL_TYPE_INTEGER, + .name = "Sharpness", + .minimum = 0, + .maximum = 2, + .step = 1, +#define SHARPNESS_DEF 1 + .default_value = SHARPNESS_DEF, + }, + .set = sd_setsharpness, + .get = sd_getsharpness, + }, }; -static struct v4l2_pix_format vc0321_mode[] = { +static const struct v4l2_pix_format vc0321_mode[] = { {320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 2, @@ -98,7 +138,7 @@ static struct v4l2_pix_format vc0321_mode[] = { .colorspace = V4L2_COLORSPACE_SRGB, .priv = 0}, }; -static struct v4l2_pix_format vc0323_mode[] = { +static const struct v4l2_pix_format vc0323_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, @@ -111,15 +151,252 @@ static struct v4l2_pix_format vc0323_mode[] = { .priv = 0}, }; -#if 0 -static const __u8 mi1310soc_gamma[17] = { - 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, - 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff +static const struct v4l2_pix_format svga_mode[] = { + {800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, + .bytesperline = 800, + .sizeimage = 800 * 600 * 1 / 4 + 590, + .colorspace = V4L2_COLORSPACE_JPEG, + .priv = 0}, }; -static const __u8 mi1310soc_matrix[9] = { - 0x56, 0xf0, 0xf6, 0xf3, 0x57, 0xf6, 0xf3, 0xef, 0x58 + +/* OV7660/7670 registers */ +#define OV7660_REG_MVFP 0x1e +#define OV7660_MVFP_MIRROR 0x20 +#define OV7660_MVFP_VFLIP 0x10 + +static const __u8 mi0360_matrix[9] = { + 0x50, 0xf8, 0xf8, 0xf5, 0x50, 0xfb, 0xff, 0xf1, 0x50 }; -#endif + +static const __u8 mi0360_initVGA_JPG[][4] = { + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x35, 0xdd, 0xcc}, + {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xbc, 0x00, 0x71, 0xcc}, + {0xb8, 0x00, 0x13, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, + {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, + {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, + {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, + {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x50, 0xcc}, + {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, + {0xb8, 0x37, 0x00, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, + {0xb8, 0x08, 0xe0, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, + {0xb8, 0x14, 0x18, 0xcc}, + {0xb8, 0xb2, 0x0a, 0xcc}, + {0xb8, 0xb4, 0x0a, 0xcc}, + {0xb8, 0xb5, 0x0a, 0xcc}, + {0xb8, 0xfe, 0x00, 0xcc}, + {0xb8, 0xff, 0x28, 0xcc}, + {0xb9, 0x00, 0x28, 0xcc}, + {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, + {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, + {0xb9, 0x05, 0x3c, 0xcc}, + {0xb9, 0x06, 0x3c, 0xcc}, + {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, + {0x31, 0x00, 0x00, 0xbb}, + {0x09, 0x01, 0xc7, 0xbb}, + {0x34, 0x01, 0x00, 0xbb}, + {0x2b, 0x00, 0x28, 0xbb}, + {0x2c, 0x00, 0x30, 0xbb}, + {0x2d, 0x00, 0x30, 0xbb}, + {0x2e, 0x00, 0x28, 0xbb}, + {0x62, 0x04, 0x11, 0xbb}, + {0x03, 0x01, 0xe0, 0xbb}, + {0x2c, 0x00, 0x2c, 0xbb}, + {0x20, 0xd0, 0x00, 0xbb}, + {0x01, 0x00, 0x08, 0xbb}, + {0x06, 0x00, 0x10, 0xbb}, + {0x05, 0x00, 0x20, 0xbb}, + {0x20, 0x00, 0x00, 0xbb}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x02, 0xcc}, + {0xb6, 0x02, 0x80, 0xcc}, + {0xb6, 0x05, 0x01, 0xcc}, + {0xb6, 0x04, 0xe0, 0xcc}, + {0xb6, 0x12, 0x78, 0xcc}, + {0xb6, 0x18, 0x02, 0xcc}, + {0xb6, 0x17, 0x58, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x10, 0xcc}, + {0xb9, 0x12, 0x00, 0xcc}, + {0xb9, 0x13, 0x0a, 0xcc}, + {0xb9, 0x14, 0x0a, 0xcc}, + {0xb9, 0x15, 0x0a, 0xcc}, + {0xb9, 0x16, 0x0a, 0xcc}, + {0xb9, 0x18, 0x00, 0xcc}, + {0xb9, 0x19, 0x0f, 0xcc}, + {0xb9, 0x1a, 0x0f, 0xcc}, + {0xb9, 0x1b, 0x0f, 0xcc}, + {0xb9, 0x1c, 0x0f, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb8, 0x0c, 0x20, 0xcc}, + {0xb8, 0x0d, 0x70, 0xcc}, + {0xb6, 0x13, 0x13, 0xcc}, + {0x35, 0x00, 0x60, 0xbb}, + {0xb3, 0x5c, 0x01, 0xcc}, + {} +}; +static const __u8 mi0360_initQVGA_JPG[][4] = { + {0xb0, 0x03, 0x19, 0xcc}, + {0xb0, 0x04, 0x02, 0xcc}, + {0xb3, 0x00, 0x24, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x03, 0xcc}, + {0xb3, 0x03, 0x0a, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x01, 0xcc}, + {0xb3, 0x23, 0xe0, 0xcc}, + {0xb3, 0x04, 0x05, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x02, 0xcc}, + {0xb3, 0x17, 0x7f, 0xcc}, + {0xb3, 0x35, 0xdd, 0xcc}, + {0xb3, 0x34, 0x02, 0xcc}, + {0xb3, 0x00, 0x25, 0xcc}, + {0xbc, 0x00, 0xd1, 0xcc}, + {0xb8, 0x00, 0x13, 0xcc}, + {0xb8, 0x27, 0x20, 0xcc}, + {0xb8, 0x2c, 0x50, 0xcc}, + {0xb8, 0x2d, 0xf8, 0xcc}, + {0xb8, 0x2e, 0xf8, 0xcc}, + {0xb8, 0x2f, 0xf8, 0xcc}, + {0xb8, 0x30, 0x50, 0xcc}, + {0xb8, 0x31, 0xf8, 0xcc}, + {0xb8, 0x32, 0xf8, 0xcc}, + {0xb8, 0x33, 0xf8, 0xcc}, + {0xb8, 0x34, 0x50, 0xcc}, + {0xb8, 0x35, 0x00, 0xcc}, + {0xb8, 0x36, 0x00, 0xcc}, + {0xb8, 0x37, 0x00, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, + {0xb8, 0x08, 0xe0, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0xb8, 0x01, 0x79, 0xcc}, + {0xb8, 0x14, 0x18, 0xcc}, + {0xb8, 0xb2, 0x0a, 0xcc}, + {0xb8, 0xb4, 0x0a, 0xcc}, + {0xb8, 0xb5, 0x0a, 0xcc}, + {0xb8, 0xfe, 0x00, 0xcc}, + {0xb8, 0xff, 0x28, 0xcc}, + {0xb9, 0x00, 0x28, 0xcc}, + {0xb9, 0x01, 0x28, 0xcc}, + {0xb9, 0x02, 0x28, 0xcc}, + {0xb9, 0x03, 0x00, 0xcc}, + {0xb9, 0x04, 0x00, 0xcc}, + {0xb9, 0x05, 0x3c, 0xcc}, + {0xb9, 0x06, 0x3c, 0xcc}, + {0xb9, 0x07, 0x3c, 0xcc}, + {0xb9, 0x08, 0x3c, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, + {0x31, 0x00, 0x00, 0xbb}, + {0x09, 0x01, 0xc7, 0xbb}, + {0x34, 0x01, 0x00, 0xbb}, + {0x2b, 0x00, 0x28, 0xbb}, + {0x2c, 0x00, 0x30, 0xbb}, + {0x2d, 0x00, 0x30, 0xbb}, + {0x2e, 0x00, 0x28, 0xbb}, + {0x62, 0x04, 0x11, 0xbb}, + {0x03, 0x01, 0xe0, 0xbb}, + {0x2c, 0x00, 0x2c, 0xbb}, + {0x20, 0xd0, 0x00, 0xbb}, + {0x01, 0x00, 0x08, 0xbb}, + {0x06, 0x00, 0x10, 0xbb}, + {0x05, 0x00, 0x20, 0xbb}, + {0x20, 0x00, 0x00, 0xbb}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x01, 0xcc}, + {0xb6, 0x02, 0x40, 0xcc}, + {0xb6, 0x05, 0x00, 0xcc}, + {0xb6, 0x04, 0xf0, 0xcc}, + {0xb6, 0x12, 0x78, 0xcc}, + {0xb6, 0x18, 0x00, 0xcc}, + {0xb6, 0x17, 0x96, 0xcc}, + {0xb6, 0x16, 0x00, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, + {0xb6, 0x23, 0x0b, 0xcc}, + {0xb3, 0x02, 0x02, 0xcc}, + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x10, 0xcc}, + {0xb9, 0x12, 0x00, 0xcc}, + {0xb9, 0x13, 0x0a, 0xcc}, + {0xb9, 0x14, 0x0a, 0xcc}, + {0xb9, 0x15, 0x0a, 0xcc}, + {0xb9, 0x16, 0x0a, 0xcc}, + {0xb9, 0x18, 0x00, 0xcc}, + {0xb9, 0x19, 0x0f, 0xcc}, + {0xb9, 0x1a, 0x0f, 0xcc}, + {0xb9, 0x1b, 0x0f, 0xcc}, + {0xb9, 0x1c, 0x0f, 0xcc}, + {0xb8, 0x8e, 0x00, 0xcc}, + {0xb8, 0x8f, 0xff, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x13, 0xcc}, + {0xbc, 0x02, 0x18, 0xcc}, + {0xbc, 0x03, 0x50, 0xcc}, + {0xbc, 0x04, 0x18, 0xcc}, + {0xbc, 0x05, 0x00, 0xcc}, + {0xbc, 0x06, 0x00, 0xcc}, + {0xbc, 0x08, 0x30, 0xcc}, + {0xbc, 0x09, 0x40, 0xcc}, + {0xbc, 0x0a, 0x10, 0xcc}, + {0xb8, 0x0c, 0x20, 0xcc}, + {0xb8, 0x0d, 0x70, 0xcc}, + {0xbc, 0x0b, 0x00, 0xcc}, + {0xbc, 0x0c, 0x00, 0xcc}, + {0x35, 0x00, 0xef, 0xbb}, + {0xb3, 0x5c, 0x01, 0xcc}, + {} +}; + static const __u8 mi1310_socinitVGA_JPG[][4] = { {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc}, @@ -832,7 +1109,7 @@ static const __u8 ov7660_initVGA_data[][4] = { {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa}, {0x00, 0x12, 0x80, 0xaa}, {0x00, 0x12, 0x05, 0xaa}, - {0x00, 0x1e, 0x01, 0xaa}, + {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */ {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */ {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */ {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa}, @@ -886,7 +1163,7 @@ static const __u8 ov7660_initQVGA_data[][4] = { {0xb8, 0x27, 0x20, 0xcc}, {0xb8, 0x8f, 0x50, 0xcc}, {0x00, 0x01, 0x80, 0xaa}, {0x00, 0x02, 0x80, 0xaa}, {0x00, 0x12, 0x80, 0xaa}, {0x00, 0x12, 0x05, 0xaa}, - {0x00, 0x1e, 0x01, 0xaa}, + {0x00, 0x1e, 0x01, 0xaa}, /* MVFP */ {0x00, 0x3d, 0x40, 0xaa}, /* 0x3d <-40 gamma 01 */ {0x00, 0x41, 0x00, 0xaa}, /* edge 00 */ {0x00, 0x0d, 0x48, 0xaa}, {0x00, 0x0e, 0x04, 0xaa}, @@ -992,7 +1269,8 @@ static const __u8 ov7670_initVGA_JPG[][4] = { {0x00, 0xa9, 0x90, 0xaa}, {0x00, 0xaa, 0x14, 0xaa}, {0x00, 0x13, 0xe5, 0xaa}, {0x00, 0x0e, 0x61, 0xaa}, {0x00, 0x0f, 0x4b, 0xaa}, {0x00, 0x16, 0x02, 0xaa}, - {0x00, 0x1e, 0x07, 0xaa}, {0x00, 0x21, 0x02, 0xaa}, + {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */ + {0x00, 0x21, 0x02, 0xaa}, {0x00, 0x22, 0x91, 0xaa}, {0x00, 0x29, 0x07, 0xaa}, {0x00, 0x33, 0x0b, 0xaa}, {0x00, 0x35, 0x0b, 0xaa}, {0x00, 0x37, 0x1d, 0xaa}, {0x00, 0x38, 0x71, 0xaa}, @@ -1057,7 +1335,8 @@ static const __u8 ov7670_initVGA_JPG[][4] = { {0x00, 0x71, 0x35, 0xaa}, {0x00, 0x72, 0x11, 0xaa}, {0x00, 0x73, 0xf0, 0xaa}, {0x00, 0xa2, 0x02, 0xaa}, {0x00, 0xb1, 0x00, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa}, - {0x00, 0x1e, 0x37, 0xaa}, {0x00, 0xaa, 0x14, 0xaa}, + {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */ + {0x00, 0xaa, 0x14, 0xaa}, {0x00, 0x24, 0x80, 0xaa}, {0x00, 0x25, 0x74, 0xaa}, {0x00, 0x26, 0xd3, 0xaa}, {0x00, 0x0d, 0x00, 0xaa}, {0x00, 0x14, 0x18, 0xaa}, {0x00, 0x9d, 0x99, 0xaa}, @@ -1119,7 +1398,8 @@ static const __u8 ov7670_initQVGA_JPG[][4] = { {0x00, 0xa9, 0x90, 0xaa}, {0x00, 0xaa, 0x14, 0xaa}, {0x00, 0x13, 0xe5, 0xaa}, {0x00, 0x0e, 0x61, 0xaa}, {0x00, 0x0f, 0x4b, 0xaa}, {0x00, 0x16, 0x02, 0xaa}, - {0x00, 0x1e, 0x07, 0xaa}, {0x00, 0x21, 0x02, 0xaa}, + {0x00, 0x1e, 0x07, 0xaa}, /* MVFP */ + {0x00, 0x21, 0x02, 0xaa}, {0x00, 0x22, 0x91, 0xaa}, {0x00, 0x29, 0x07, 0xaa}, {0x00, 0x33, 0x0b, 0xaa}, {0x00, 0x35, 0x0b, 0xaa}, {0x00, 0x37, 0x1d, 0xaa}, {0x00, 0x38, 0x71, 0xaa}, @@ -1184,7 +1464,8 @@ static const __u8 ov7670_initQVGA_JPG[][4] = { {0x00, 0x71, 0x35, 0xaa}, {0x00, 0x72, 0x11, 0xaa}, {0x00, 0x73, 0xf0, 0xaa}, {0x00, 0xa2, 0x02, 0xaa}, {0x00, 0xb1, 0x00, 0xaa}, {0x00, 0xb1, 0x0c, 0xaa}, - {0x00, 0x1e, 0x37, 0xaa}, {0x00, 0xaa, 0x14, 0xaa}, + {0x00, 0x1e, 0x37, 0xaa}, /* MVFP */ + {0x00, 0xaa, 0x14, 0xaa}, {0x00, 0x24, 0x80, 0xaa}, {0x00, 0x25, 0x74, 0xaa}, {0x00, 0x26, 0xd3, 0xaa}, {0x00, 0x0d, 0x00, 0xaa}, {0x00, 0x14, 0x18, 0xaa}, {0x00, 0x9d, 0x99, 0xaa}, @@ -1212,177 +1493,301 @@ static const __u8 ov7670_initQVGA_JPG[][4] = { {0x00, 0x77, 0x05, 0xaa }, {}, }; + +/* PO1200 - values from usbvm326.inf and ms-win trace */ +static const __u8 po1200_gamma[17] = { +#if 1 + 0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8, + 0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff +#else +/*ms-win trace*/ + 0x01, 0x0b, 0x1e, 0x38, 0x51, 0x6b, 0x83, 0x9a, 0xaf, + 0xc1, 0xd0, 0xdd, 0xe8, 0xf2, 0xf9, 0xff, 0xff +#endif +}; +static const __u8 po1200_matrix[9] = { + 0x60, 0xf9, 0xe5, 0xe7, 0x50, 0x05, 0xf3, 0xe6, 0x5e +}; +static const __u8 po1200_initVGA_data[][4] = { + {0xb0, 0x03, 0x19, 0xcc}, /* reset? */ #if 0 -static const __u8 ov7670_initQVGA_JPG[][4] = { - {0xb3, 0x00, 0x00, 0xcc}, - {0xb0, 0x16, 0x0d, 0xcc}, - {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x16, 0x00, 0xcc}, - {0x00, 0x00, 0x50, 0xdd}, {0xb0, 0x03, 0x19, 0xcc}, - {0x00, 0x00, 0x50, 0xdd}, {0xb3, 0x49, 0x11, 0xcc}, - {0xb3, 0x49, 0x00, 0xcc}, {0xb0, 0x16, 0x00, 0xcc}, - - {0xb3, 0x01, 0x05, 0xcc}, {0x00, 0x00, 0x50, 0xdd}, - {0xb0, 0x03, 0x19, 0xcc}, {0xb0, 0x04, 0x02, 0xcc}, - {0x00, 0x00, 0x50, 0xdd}, {0xb3, 0x00, 0x66, 0xcc}, - {0xb3, 0x00, 0x67, 0xcc}, {0xb3, 0x35, 0xa1, 0xcc}, - {0xb3, 0x34, 0x01, 0xcc}, {0xb3, 0x05, 0x01, 0xcc}, - {0xb3, 0x06, 0x01, 0xcc}, {0xb3, 0x08, 0x01, 0xcc}, - {0xb3, 0x09, 0x0c, 0xcc}, {0xb3, 0x02, 0x02, 0xcc}, - {0xb3, 0x03, 0x1f, 0xcc}, {0xb3, 0x14, 0x00, 0xcc}, - {0xb3, 0x15, 0x00, 0xcc}, {0xb3, 0x16, 0x02, 0xcc}, - {0xb3, 0x17, 0x7f, 0xcc}, {0xb3, 0x04, 0x05, 0xcc}, - {0xb3, 0x20, 0x00, 0xcc}, {0xb3, 0x21, 0x00, 0xcc}, - {0xb3, 0x22, 0x01, 0xcc}, {0xb3, 0x23, 0xe0, 0xcc}, - {0xbc, 0x00, 0xd1, 0xcc}, /* set QVGA */ - {0xbc, 0x01, 0x01, 0xcc},/* */ - {0x00, 0x12, 0x80, 0xaa},/* OV sensor reset */ - {0x00, 0x00, 0x50, 0xdd},/* wait sometimes */ - {0, 0x12, 0x00, 0xaa}, - {0, 0x11, 0x40, 0xaa}, {0, 0x6b, 0x0a, 0xaa}, - {0, 0x3a, 0x04, 0xaa}, {0, 0x40, 0xc0, 0xaa}, - {0, 0x8c, 0x00, 0xaa}, {0, 0x7a, 0x29, 0xaa}, - {0, 0x7b, 0x0e, 0xaa}, {0, 0x7c, 0x1a, 0xaa}, - {0, 0x7d, 0x31, 0xaa}, {0, 0x7e, 0x53, 0xaa}, - {0, 0x7f, 0x60, 0xaa}, {0, 0x80, 0x6b, 0xaa}, - {0, 0x81, 0x73, 0xaa}, {0, 0x82, 0x7b, 0xaa}, - {0, 0x83, 0x82, 0xaa}, {0, 0x84, 0x89, 0xaa}, - {0, 0x85, 0x96, 0xaa}, {0, 0x86, 0xa1, 0xaa}, - {0, 0x87, 0xb7, 0xaa}, {0, 0x88, 0xcc, 0xaa}, - {0, 0x89, 0xe1, 0xaa}, {0, 0x13, 0xe0, 0xaa}, - {0, 0x00, 0x00, 0xaa}, {0, 0x10, 0x00, 0xaa}, - {0, 0x0d, 0x40, 0xaa}, {0, 0x14, 0x28, 0xaa}, - {0, 0xa5, 0x05, 0xaa}, {0, 0xab, 0x07, 0xaa}, - {0, 0x24, 0x95, 0xaa}, {0, 0x25, 0x33, 0xaa}, - {0, 0x26, 0xe3, 0xaa}, {0, 0x9f, 0x88, 0xaa}, - {0, 0xa0, 0x78, 0xaa}, {0, 0x55, 0x90, 0xaa}, - {0, 0xa1, 0x03, 0xaa}, {0, 0xa6, 0xe0, 0xaa}, - {0, 0xa7, 0xd8, 0xaa}, {0, 0xa8, 0xf0, 0xaa}, - {0, 0xa9, 0x90, 0xaa}, {0, 0xaa, 0x14, 0xaa}, - {0, 0x13, 0xe5, 0xaa}, {0, 0x0e, 0x61, 0xaa}, - {0, 0x0f, 0x4b, 0xaa}, {0, 0x16, 0x02, 0xaa}, - {0, 0x1e, 0x07, 0xaa}, {0, 0x21, 0x02, 0xaa}, - {0, 0x22, 0x91, 0xaa}, {0, 0x29, 0x07, 0xaa}, - {0, 0x33, 0x0b, 0xaa}, {0, 0x35, 0x0b, 0xaa}, - {0, 0x37, 0x1d, 0xaa}, {0, 0x38, 0x71, 0xaa}, - {0, 0x39, 0x2a, 0xaa}, {0, 0x3c, 0x78, 0xaa}, - {0, 0x4d, 0x40, 0xaa}, {0, 0x4e, 0x20, 0xaa}, - {0, 0x74, 0x19, 0xaa}, {0, 0x8d, 0x4f, 0xaa}, - {0, 0x8e, 0x00, 0xaa}, {0, 0x8f, 0x00, 0xaa}, - {0, 0x90, 0x00, 0xaa}, {0, 0x91, 0x00, 0xaa}, - {0, 0x96, 0x00, 0xaa}, {0, 0x9a, 0x80, 0xaa}, - {0, 0xb0, 0x84, 0xaa}, {0, 0xb1, 0x0c, 0xaa}, - {0, 0xb2, 0x0e, 0xaa}, {0, 0xb3, 0x82, 0xaa}, - {0, 0xb8, 0x0a, 0xaa}, {0, 0x43, 0x14, 0xaa}, - {0, 0x44, 0xf0, 0xaa}, {0, 0x45, 0x45, 0xaa}, - {0, 0x46, 0x63, 0xaa}, {0, 0x47, 0x2d, 0xaa}, - {0, 0x48, 0x46, 0xaa}, {0, 0x59, 0x88, 0xaa}, - {0, 0x5a, 0xa0, 0xaa}, {0, 0x5b, 0xc6, 0xaa}, - {0, 0x5c, 0x7d, 0xaa}, {0, 0x5d, 0x5f, 0xaa}, - {0, 0x5e, 0x19, 0xaa}, {0, 0x6c, 0x0a, 0xaa}, - {0, 0x6d, 0x55, 0xaa}, {0, 0x6e, 0x11, 0xaa}, - {0, 0x6f, 0x9e, 0xaa}, {0, 0x69, 0x00, 0xaa}, - {0, 0x6a, 0x40, 0xaa}, {0, 0x01, 0x40, 0xaa}, - {0, 0x02, 0x40, 0xaa}, {0, 0x13, 0xe7, 0xaa}, - {0, 0x5f, 0xf0, 0xaa}, {0, 0x60, 0xf0, 0xaa}, - {0, 0x61, 0xf0, 0xaa}, {0, 0x27, 0xa0, 0xaa}, - {0, 0x28, 0x80, 0xaa}, {0, 0x2c, 0x90, 0xaa}, - {0, 0x4f, 0x66, 0xaa}, {0, 0x50, 0x66, 0xaa}, - {0, 0x51, 0x00, 0xaa}, {0, 0x52, 0x22, 0xaa}, - {0, 0x53, 0x5e, 0xaa}, {0, 0x54, 0x80, 0xaa}, - {0, 0x58, 0x9e, 0xaa}, {0, 0x41, 0x08, 0xaa}, - {0, 0x3f, 0x00, 0xaa}, {0, 0x75, 0x85, 0xaa}, - {0, 0x76, 0xe1, 0xaa}, {0, 0x4c, 0x00, 0xaa}, - {0, 0x77, 0x0a, 0xaa}, {0, 0x3d, 0x88, 0xaa}, - {0, 0x4b, 0x09, 0xaa}, {0, 0xc9, 0x60, 0xaa}, - {0, 0x41, 0x38, 0xaa}, {0, 0x62, 0x30, 0xaa}, - {0, 0x63, 0x30, 0xaa}, {0, 0x64, 0x08, 0xaa}, - {0, 0x94, 0x07, 0xaa}, {0, 0x95, 0x0b, 0xaa}, - {0, 0x65, 0x00, 0xaa}, {0, 0x66, 0x05, 0xaa}, - {0, 0x56, 0x50, 0xaa}, {0, 0x34, 0x11, 0xaa}, - {0, 0xa4, 0x88, 0xaa}, {0, 0x96, 0x00, 0xaa}, - {0, 0x97, 0x30, 0xaa}, {0, 0x98, 0x20, 0xaa}, - {0, 0x99, 0x30, 0xaa}, {0, 0x9a, 0x84, 0xaa}, - {0, 0x9b, 0x29, 0xaa}, {0, 0x9c, 0x03, 0xaa}, - {0, 0x78, 0x04, 0xaa}, {0, 0x79, 0x01, 0xaa}, - {0, 0xc8, 0xf0, 0xaa}, {0, 0x79, 0x0f, 0xaa}, - {0, 0xc8, 0x00, 0xaa}, {0, 0x79, 0x10, 0xaa}, - {0, 0xc8, 0x7e, 0xaa}, {0, 0x79, 0x0a, 0xaa}, - {0, 0xc8, 0x80, 0xaa}, {0, 0x79, 0x0b, 0xaa}, - {0, 0xc8, 0x01, 0xaa}, {0, 0x79, 0x0c, 0xaa}, - {0, 0xc8, 0x0f, 0xaa}, {0, 0x79, 0x0d, 0xaa}, - {0, 0xc8, 0x20, 0xaa}, {0, 0x79, 0x09, 0xaa}, - {0, 0xc8, 0x80, 0xaa}, {0, 0x79, 0x02, 0xaa}, - {0, 0xc8, 0xc0, 0xaa}, {0, 0x79, 0x03, 0xaa}, - {0, 0xc8, 0x40, 0xaa}, {0, 0x79, 0x05, 0xaa}, - {0, 0xc8, 0x30, 0xaa}, {0, 0x79, 0x26, 0xaa}, - {0, 0x11, 0x40, 0xaa}, {0, 0x3a, 0x04, 0xaa}, - {0, 0x12, 0x00, 0xaa}, {0, 0x40, 0xc0, 0xaa}, - {0, 0x8c, 0x00, 0xaa}, {0, 0x17, 0x14, 0xaa}, - {0, 0x18, 0x02, 0xaa}, {0, 0x32, 0x92, 0xaa}, - {0, 0x19, 0x02, 0xaa}, {0, 0x1a, 0x7a, 0xaa}, - {0, 0x03, 0x0a, 0xaa}, {0, 0x0c, 0x00, 0xaa}, - {0, 0x3e, 0x00, 0xaa}, {0, 0x70, 0x3a, 0xaa}, - {0, 0x71, 0x35, 0xaa}, {0, 0x72, 0x11, 0xaa}, - {0, 0x73, 0xf0, 0xaa}, {0, 0xa2, 0x02, 0xaa}, - {0, 0xb1, 0x00, 0xaa}, {0, 0xb1, 0x0c, 0xaa}, - {0, 0x1e, 0x37, 0xaa}, {0, 0xaa, 0x14, 0xaa}, - {0, 0x24, 0x80, 0xaa}, {0, 0x25, 0x74, 0xaa}, - {0, 0x26, 0xd3, 0xaa}, {0, 0x0d, 0x00, 0xaa}, - {0, 0x14, 0x18, 0xaa}, {0, 0x9d, 0x99, 0xaa}, - {0, 0x9e, 0x7f, 0xaa}, {0, 0x64, 0x08, 0xaa}, - {0, 0x94, 0x07, 0xaa}, {0, 0x95, 0x06, 0xaa}, - {0, 0x66, 0x05, 0xaa}, {0, 0x41, 0x08, 0xaa}, - {0, 0x3f, 0x00, 0xaa}, {0, 0x75, 0x07, 0xaa}, - {0, 0x76, 0xe1, 0xaa}, {0, 0x4c, 0x00, 0xaa}, - {0, 0x77, 0x00, 0xaa}, {0, 0x3d, 0xc2, 0xaa}, - {0, 0x4b, 0x09, 0xaa}, {0, 0xc9, 0x60, 0xaa}, - {0, 0x41, 0x38, 0xaa}, - {0xb6, 0x00, 0x00, 0xcc}, {0xb6, 0x03, 0x01, 0xcc}, - {0xb6, 0x02, 0x40, 0xcc}, - {0xb6, 0x05, 0x00, 0xcc}, {0xb6, 0x04, 0xf0, 0xcc}, - {0xb6, 0x12, 0xf8, 0xcc}, {0xb6, 0x13, 0x21, 0xcc}, - {0xb6, 0x18, 0x00, 0xcc}, {0xb6, 0x17, 0x96, 0xcc}, - {0xb6, 0x16, 0x00, 0xcc}, {0xb6, 0x22, 0x12, 0xcc}, + {0x00, 0x00, 0x64, 0xdd}, + {0xb3, 0x49, 0x11, 0xcc}, + {0x00, 0x00, 0x33, 0xdd}, +/*read b349*/ +#endif + {0xb0, 0x03, 0x19, 0xcc}, +/* {0x00, 0x00, 0x33, 0xdd}, */ + {0xb0, 0x04, 0x02, 0xcc}, + {0xb0, 0x02, 0x02, 0xcc}, + {0xb3, 0x5d, 0x00, 0xcc}, + {0xb3, 0x01, 0x01, 0xcc}, + {0xb3, 0x00, 0x64, 0xcc}, + {0xb3, 0x00, 0x65, 0xcc}, + {0xb3, 0x05, 0x01, 0xcc}, + {0xb3, 0x06, 0x01, 0xcc}, + {0xb3, 0x5c, 0x01, 0xcc}, + {0xb3, 0x08, 0x01, 0xcc}, + {0xb3, 0x09, 0x0c, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb3, 0x02, 0xb2, 0xcc}, + {0xb3, 0x03, 0x18, 0xcc}, + {0xb3, 0x04, 0x15, 0xcc}, + {0xb3, 0x20, 0x00, 0xcc}, + {0xb3, 0x21, 0x00, 0xcc}, + {0xb3, 0x22, 0x02, 0xcc}, + {0xb3, 0x23, 0x58, 0xcc}, + {0xb3, 0x14, 0x00, 0xcc}, + {0xb3, 0x15, 0x00, 0xcc}, + {0xb3, 0x16, 0x03, 0xcc}, + {0xb3, 0x17, 0x1f, 0xcc}, + {0xbc, 0x00, 0x71, 0xcc}, + {0xbc, 0x01, 0x01, 0xcc}, + {0xb0, 0x54, 0x13, 0xcc}, + {0xb3, 0x00, 0x67, 0xcc}, + {0xb3, 0x34, 0x01, 0xcc}, + {0xb3, 0x35, 0xdc, 0xcc}, + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x12, 0x05, 0xaa}, + {0x00, 0x13, 0x02, 0xaa}, + {0x00, 0x1e, 0xc6, 0xaa}, /* h/v flip */ + {0x00, 0x21, 0x00, 0xaa}, + {0x00, 0x25, 0x02, 0xaa}, + {0x00, 0x3c, 0x4f, 0xaa}, + {0x00, 0x3f, 0xe0, 0xaa}, + {0x00, 0x42, 0xff, 0xaa}, + {0x00, 0x45, 0x34, 0xaa}, + {0x00, 0x55, 0xfe, 0xaa}, + {0x00, 0x59, 0xd3, 0xaa}, + {0x00, 0x5e, 0x04, 0xaa}, + {0x00, 0x61, 0xb8, 0xaa}, /* sharpness */ + {0x00, 0x62, 0x02, 0xaa}, + {0x00, 0xa7, 0x31, 0xaa}, + {0x00, 0xa9, 0x66, 0xaa}, + {0x00, 0xb0, 0x00, 0xaa}, + {0x00, 0xb1, 0x00, 0xaa}, + {0x00, 0xb3, 0x11, 0xaa}, + {0x00, 0xb6, 0x26, 0xaa}, + {0x00, 0xb7, 0x20, 0xaa}, + {0x00, 0xba, 0x04, 0xaa}, + {0x00, 0x88, 0x42, 0xaa}, + {0x00, 0x89, 0x9a, 0xaa}, + {0x00, 0x8a, 0x88, 0xaa}, + {0x00, 0x8b, 0x8e, 0xaa}, + {0x00, 0x8c, 0x3e, 0xaa}, + {0x00, 0x8d, 0x90, 0xaa}, + {0x00, 0x8e, 0x87, 0xaa}, + {0x00, 0x8f, 0x96, 0xaa}, + {0x00, 0x90, 0x3d, 0xaa}, + {0x00, 0x64, 0x00, 0xaa}, + {0x00, 0x65, 0x10, 0xaa}, + {0x00, 0x66, 0x20, 0xaa}, + {0x00, 0x67, 0x2b, 0xaa}, + {0x00, 0x68, 0x36, 0xaa}, + {0x00, 0x69, 0x49, 0xaa}, + {0x00, 0x6a, 0x5a, 0xaa}, + {0x00, 0x6b, 0x7f, 0xaa}, + {0x00, 0x6c, 0x9b, 0xaa}, + {0x00, 0x6d, 0xba, 0xaa}, + {0x00, 0x6e, 0xd4, 0xaa}, + {0x00, 0x6f, 0xea, 0xaa}, + {0x00, 0x70, 0x00, 0xaa}, + {0x00, 0x71, 0x10, 0xaa}, + {0x00, 0x72, 0x20, 0xaa}, + {0x00, 0x73, 0x2b, 0xaa}, + {0x00, 0x74, 0x36, 0xaa}, + {0x00, 0x75, 0x49, 0xaa}, + {0x00, 0x76, 0x5a, 0xaa}, + {0x00, 0x77, 0x7f, 0xaa}, + {0x00, 0x78, 0x9b, 0xaa}, + {0x00, 0x79, 0xba, 0xaa}, + {0x00, 0x7a, 0xd4, 0xaa}, + {0x00, 0x7b, 0xea, 0xaa}, + {0x00, 0x7c, 0x00, 0xaa}, + {0x00, 0x7d, 0x10, 0xaa}, + {0x00, 0x7e, 0x20, 0xaa}, + {0x00, 0x7f, 0x2b, 0xaa}, + {0x00, 0x80, 0x36, 0xaa}, + {0x00, 0x81, 0x49, 0xaa}, + {0x00, 0x82, 0x5a, 0xaa}, + {0x00, 0x83, 0x7f, 0xaa}, + {0x00, 0x84, 0x9b, 0xaa}, + {0x00, 0x85, 0xba, 0xaa}, + {0x00, 0x86, 0xd4, 0xaa}, + {0x00, 0x87, 0xea, 0xaa}, + {0x00, 0x57, 0x2a, 0xaa}, + {0x00, 0x03, 0x01, 0xaa}, + {0x00, 0x04, 0x10, 0xaa}, + {0x00, 0x05, 0x10, 0xaa}, + {0x00, 0x06, 0x10, 0xaa}, + {0x00, 0x07, 0x10, 0xaa}, + {0x00, 0x08, 0x13, 0xaa}, + {0x00, 0x0a, 0x00, 0xaa}, + {0x00, 0x0b, 0x10, 0xaa}, + {0x00, 0x0c, 0x20, 0xaa}, + {0x00, 0x0d, 0x18, 0xaa}, + {0x00, 0x22, 0x01, 0xaa}, + {0x00, 0x23, 0x60, 0xaa}, + {0x00, 0x25, 0x08, 0xaa}, + {0x00, 0x26, 0x82, 0xaa}, + {0x00, 0x2e, 0x0f, 0xaa}, + {0x00, 0x2f, 0x1e, 0xaa}, + {0x00, 0x30, 0x2d, 0xaa}, + {0x00, 0x31, 0x3c, 0xaa}, + {0x00, 0x32, 0x4b, 0xaa}, + {0x00, 0x33, 0x5a, 0xaa}, + {0x00, 0x34, 0x69, 0xaa}, + {0x00, 0x35, 0x78, 0xaa}, + {0x00, 0x36, 0x87, 0xaa}, + {0x00, 0x37, 0x96, 0xaa}, + {0x00, 0x38, 0xa5, 0xaa}, + {0x00, 0x39, 0xb4, 0xaa}, + {0x00, 0x3a, 0xc3, 0xaa}, + {0x00, 0x3b, 0xd2, 0xaa}, + {0x00, 0x3c, 0xe1, 0xaa}, + {0x00, 0x3e, 0xff, 0xaa}, + {0x00, 0x3f, 0xff, 0xaa}, + {0x00, 0x40, 0xff, 0xaa}, + {0x00, 0x41, 0xff, 0xaa}, + {0x00, 0x42, 0xff, 0xaa}, + {0x00, 0x43, 0xff, 0xaa}, + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x20, 0xc4, 0xaa}, + {0x00, 0x13, 0x03, 0xaa}, + {0x00, 0x3c, 0x50, 0xaa}, + {0x00, 0x61, 0x6a, 0xaa}, /* sharpness? */ + {0x00, 0x51, 0x5b, 0xaa}, + {0x00, 0x52, 0x91, 0xaa}, + {0x00, 0x53, 0x4c, 0xaa}, + {0x00, 0x54, 0x50, 0xaa}, + {0x00, 0x56, 0x02, 0xaa}, + {0xb6, 0x00, 0x00, 0xcc}, + {0xb6, 0x03, 0x03, 0xcc}, + {0xb6, 0x02, 0x20, 0xcc}, + {0xb6, 0x05, 0x02, 0xcc}, + {0xb6, 0x04, 0x58, 0xcc}, + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x21, 0xcc}, + {0xb6, 0x18, 0x03, 0xcc}, + {0xb6, 0x17, 0xa9, 0xcc}, + {0xb6, 0x16, 0x80, 0xcc}, + {0xb6, 0x22, 0x12, 0xcc}, {0xb6, 0x23, 0x0b, 0xcc}, - {0xbf, 0xc0, 0x39, 0xcc},/* set jpeg */ - {0xbf, 0xc1, 0x04, 0xcc},/* */ - {0xbf, 0xcc, 0x00, 0xcc},/* */ - {0xbc, 0x02, 0x18, 0xcc}, {0xbc, 0x03, 0x50, 0xcc}, - {0xbc, 0x04, 0x18, 0xcc}, {0xbc, 0x05, 0x00, 0xcc}, - {0xbc, 0x06, 0x00, 0xcc}, {0xbc, 0x08, 0x30, 0xcc}, - {0xbc, 0x09, 0x40, 0xcc}, {0xbc, 0x0a, 0x10, 0xcc}, - {0xbc, 0x0b, 0x00, 0xcc}, {0xbc, 0x0c, 0x00, 0xcc}, - {0xb3, 0x5c, 0x01, 0xcc}, {0xb3, 0x01, 0x45, 0xcc}, - {0, 0x77, 0x05, 0xaa}, {0xb6, 0x12, 0xf8, 0xcc}, - {0xb6, 0x13, 0x20, 0xcc}, - {0, 0x24, 0x6c, 0xaa}, - {0, 0x25, 0x5c, 0xaa}, {0, 0x56, 0x50, 0xaa}, - {0, 0x4f, 0xa8, 0xaa}, {0, 0x50, 0xa5, 0xaa}, - {0, 0x51, 0x02, 0xaa}, {0, 0x52, 0x22, 0xaa}, - {0, 0x53, 0x86, 0xaa}, {0, 0x54, 0xaa, 0xaa}, - {0, 0x7a, 0x19, 0xaa}, {0, 0x7b, 0x0c, 0xaa}, - {0, 0x7c, 0x18, 0xaa}, {0, 0x7d, 0x2f, 0xaa}, - {0, 0x7e, 0x54, 0xaa}, {0, 0x7f, 0x64, 0xaa}, - {0, 0x80, 0x71, 0xaa}, {0, 0x81, 0x7d, 0xaa}, - {0, 0x82, 0x88, 0xaa}, {0, 0x83, 0x91, 0xaa}, - {0, 0x84, 0x98, 0xaa}, {0, 0x85, 0xa7, 0xaa}, - {0, 0x86, 0xb4, 0xaa}, {0, 0x87, 0xcb, 0xaa}, - {0, 0x88, 0xde, 0xaa}, {0, 0x89, 0xed, 0xaa}, - {0, 0x75, 0x86, 0xaa}, {0, 0x92, 0x00, 0xaa}, - {0, 0x3b, 0, 0xbb}, - {0, 0x3b, 0x00, 0xaa}, - {0, 0x13, 0, 0xbb}, {0, 0x13, 0xe7, 0xaa}, - {0, 0x2d, 0x00, 0xaa}, {0, 0x2e, 0x00, 0xaa}, - {0, 0x04, 0x00, 0xaa}, {0, 0x10, 0x00, 0xaa}, - {0, 0x3b, 0, 0xbb}, {0, 0x3b, 0x80, 0xaa}, - {0, 0x13, 0, 0xbb}, - {0, 0x13, 0xe7, 0xaa}, - {0, 0x1e, 0x27, 0xaa}, - {0, 0x1e, 0x27, 0xaa}, - {0, 0x3b, 0xc8, 0xaa}, - {} -}; + {0xbf, 0xc0, 0x39, 0xcc}, + {0xbf, 0xc1, 0x04, 0xcc}, + {0xbf, 0xcc, 0x00, 0xcc}, + {0xb8, 0x06, 0x20, 0xcc}, + {0xb8, 0x07, 0x03, 0xcc}, + {0xb8, 0x08, 0x58, 0xcc}, + {0xb8, 0x09, 0x02, 0xcc}, + {0xb3, 0x01, 0x41, 0xcc}, + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0xd9, 0x0f, 0xaa}, + {0x00, 0xda, 0xaa, 0xaa}, + {0x00, 0xd9, 0x10, 0xaa}, + {0x00, 0xda, 0xaa, 0xaa}, + {0x00, 0xd9, 0x11, 0xaa}, + {0x00, 0xda, 0x00, 0xaa}, + {0x00, 0xd9, 0x12, 0xaa}, + {0x00, 0xda, 0xff, 0xaa}, + {0x00, 0xd9, 0x13, 0xaa}, + {0x00, 0xda, 0xff, 0xaa}, + {0x00, 0xe8, 0x11, 0xaa}, + {0x00, 0xe9, 0x12, 0xaa}, + {0x00, 0xea, 0x5c, 0xaa}, + {0x00, 0xeb, 0xff, 0xaa}, + {0x00, 0xd8, 0x80, 0xaa}, + {0x00, 0xe6, 0x02, 0xaa}, + {0x00, 0xd6, 0x40, 0xaa}, + {0x00, 0xe3, 0x05, 0xaa}, + {0x00, 0xe0, 0x40, 0xaa}, + {0x00, 0xde, 0x03, 0xaa}, + {0x00, 0xdf, 0x03, 0xaa}, + {0x00, 0xdb, 0x02, 0xaa}, + {0x00, 0xdc, 0x00, 0xaa}, + {0x00, 0xdd, 0x03, 0xaa}, + {0x00, 0xe1, 0x08, 0xaa}, + {0x00, 0xe2, 0x01, 0xaa}, + {0x00, 0xd6, 0x40, 0xaa}, + {0x00, 0xe4, 0x40, 0xaa}, +#if 1 + {0x00, 0xa8, 0x8f, 0xaa}, +#else +/*modified later*/ + {0x00, 0xa8, 0x9f, 0xaa}, +#endif + {0x00, 0xb4, 0x16, 0xaa}, + {0xb0, 0x02, 0x06, 0xcc}, + {0xb0, 0x18, 0x06, 0xcc}, + {0xb0, 0x19, 0x06, 0xcc}, + {0xb3, 0x5d, 0x18, 0xcc}, + {0xb3, 0x05, 0x00, 0xcc}, + {0xb3, 0x06, 0x00, 0xcc}, + {0x00, 0xb4, 0x0e, 0xaa}, + {0x00, 0xb5, 0x49, 0xaa}, + {0x00, 0xb6, 0x1c, 0xaa}, + {0x00, 0xb7, 0x96, 0xaa}, +/* end of usbvm326.inf - start of ms-win trace */ + {0xb6, 0x12, 0xf8, 0xcc}, + {0xb6, 0x13, 0x3d, 0xcc}, +/*read b306*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x1a, 0x09, 0xaa}, + {0x00, 0x1b, 0x8a, 0xaa}, +/*read b827*/ + {0xb8, 0x27, 0x00, 0xcc}, + {0xb8, 0x26, 0x60, 0xcc}, + {0xb8, 0x26, 0x60, 0xcc}, +/*gamma - to do?*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0xae, 0x84, 0xaa}, +/*gamma again*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x96, 0xa0, 0xaa}, +/*matrix*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x91, 0x35, 0xaa}, + {0x00, 0x92, 0x22, 0xaa}, +/*gamma*/ + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x95, 0x85, 0xaa}, +/*matrix*/ +#if 0 + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x61, 0xb8, 0xaa}, /* sharpness */ +#endif + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x4d, 0x20, 0xaa}, + {0xb8, 0x22, 0x40, 0xcc}, + {0xb8, 0x23, 0x40, 0xcc}, + {0xb8, 0x24, 0x40, 0xcc}, + {0xb8, 0x81, 0x09, 0xcc}, + {0x00, 0x00, 0x64, 0xdd}, + {0x00, 0x03, 0x01, 0xaa}, +/*read 46*/ + {0x00, 0x46, 0x3c, 0xaa}, + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x16, 0x40, 0xaa}, + {0x00, 0x17, 0x40, 0xaa}, + {0x00, 0x18, 0x40, 0xaa}, + {0x00, 0x19, 0x41, 0xaa}, + {0x00, 0x03, 0x01, 0xaa}, + {0x00, 0x46, 0x3c, 0xaa}, + {0x00, 0x00, 0x18, 0xdd}, +/*read bfff*/ +#if 0 + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0x1e, 0x46, 0xaa}, /* h/v flip */ + {0x00, 0xa8, 0x8f, 0xaa}, #endif + {0x00, 0x03, 0x00, 0xaa}, + {0x00, 0xb4, 0x1c, 0xaa}, + {0x00, 0xb5, 0x92, 0xaa}, + {0x00, 0xb6, 0x39, 0xaa}, + {0x00, 0xb7, 0x24, 0xaa}, +/*write 89 0400 1415*/ +}; struct sensor_info { int sensorId; @@ -1402,6 +1807,9 @@ static const struct sensor_info sensor_info_data[] = { {SENSOR_MI1320, 0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01}, {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05}, {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x143a, 0x24, 0x25, 0x01}, +/* (tested in vc032x_probe_sensor) */ +/* {SENSOR_MI0360, 0x80 | 0x5d, 0x00, 0x8243, 0x24, 0x25, 0x01}, */ + {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01}, }; /* read 'len' bytes in gspca_dev->usb_buf */ @@ -1458,18 +1866,18 @@ static void read_sensor_register(struct gspca_dev *gspca_dev, msleep(1); } reg_r(gspca_dev, 0xa1, 0xb33e, 1); - hdata = gspca_dev->usb_buf[0]; + ldata = gspca_dev->usb_buf[0]; reg_r(gspca_dev, 0xa1, 0xb33d, 1); mdata = gspca_dev->usb_buf[0]; reg_r(gspca_dev, 0xa1, 0xb33c, 1); - ldata = gspca_dev->usb_buf[0]; - PDEBUG(D_PROBE, "Read Sensor h (0x%02X) m (0x%02X) l (0x%02X)", + hdata = gspca_dev->usb_buf[0]; + PDEBUG(D_PROBE, "Read Sensor %02x%02x %02x", hdata, mdata, ldata); reg_r(gspca_dev, 0xa1, 0xb334, 1); if (gspca_dev->usb_buf[0] == 0x02) - *value = (ldata << 8) + mdata; + *value = (hdata << 8) + mdata; else - *value = ldata; + *value = hdata; } static int vc032x_probe_sensor(struct gspca_dev *gspca_dev) @@ -1480,7 +1888,7 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev) const struct sensor_info *ptsensor_info; reg_r(gspca_dev, 0xa1, 0xbfcf, 1); - PDEBUG(D_PROBE, "check sensor header %d", gspca_dev->usb_buf[0]); + PDEBUG(D_PROBE, "check sensor header %02x", gspca_dev->usb_buf[0]); for (i = 0; i < ARRAY_SIZE(sensor_info_data); i++) { ptsensor_info = &sensor_info_data[i]; reg_w(dev, 0xa0, 0x02, 0xb334); @@ -1489,16 +1897,15 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev) reg_w(dev, 0xa0, 0x01, 0xb308); reg_w(dev, 0xa0, 0x0c, 0xb309); reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335); -/* PDEBUG(D_PROBE, - "check sensor VC032X -> %d Add -> ox%02X!", - i, ptsensor_info->I2cAdd); */ reg_w(dev, 0xa0, ptsensor_info->op, 0xb301); read_sensor_register(gspca_dev, ptsensor_info->IdAdd, &value); - if (value == ptsensor_info->VpId) { -/* PDEBUG(D_PROBE, "find sensor VC032X -> ox%04X!", - ptsensor_info->VpId); */ + if (value == ptsensor_info->VpId) return ptsensor_info->sensorId; - } + + /* special case for MI0360 */ + if (ptsensor_info->sensorId == SENSOR_MI1310_SOC + && value == 0x8243) + return SENSOR_MI0360; } return -1; } @@ -1600,13 +2007,6 @@ static int sd_config(struct gspca_dev *gspca_dev, cam = &gspca_dev->cam; cam->epaddr = 0x02; sd->bridge = id->driver_info; - if (sd->bridge == BRIDGE_VC0321) { - cam->cam_mode = vc0321_mode; - cam->nmodes = ARRAY_SIZE(vc0321_mode); - } else { - cam->cam_mode = vc0323_mode; - cam->nmodes = ARRAY_SIZE(vc0323_mode); - } vc0321_reset(gspca_dev); sensor = vc032x_probe_sensor(gspca_dev); @@ -1616,35 +2016,66 @@ static int sd_config(struct gspca_dev *gspca_dev, return -EINVAL; case SENSOR_HV7131R: PDEBUG(D_PROBE, "Find Sensor HV7131R"); - sd->sensor = SENSOR_HV7131R; + break; + case SENSOR_MI0360: + PDEBUG(D_PROBE, "Find Sensor MI0360"); + sd->bridge = BRIDGE_VC0323; break; case SENSOR_MI1310_SOC: PDEBUG(D_PROBE, "Find Sensor MI1310_SOC"); - sd->sensor = SENSOR_MI1310_SOC; break; case SENSOR_MI1320: PDEBUG(D_PROBE, "Find Sensor MI1320"); - sd->sensor = SENSOR_MI1320; break; case SENSOR_OV7660: PDEBUG(D_PROBE, "Find Sensor OV7660"); - sd->sensor = SENSOR_OV7660; break; case SENSOR_OV7670: PDEBUG(D_PROBE, "Find Sensor OV7670"); - sd->sensor = SENSOR_OV7670; + break; + case SENSOR_PO1200: + PDEBUG(D_PROBE, "Find Sensor PO1200"); break; case SENSOR_PO3130NC: PDEBUG(D_PROBE, "Find Sensor PO3130NC"); - sd->sensor = SENSOR_PO3130NC; break; } + sd->sensor = sensor; - sd->qindex = 7; - sd->autogain = AUTOGAIN_DEF; + if (sd->bridge == BRIDGE_VC0321) { + cam->cam_mode = vc0321_mode; + cam->nmodes = ARRAY_SIZE(vc0321_mode); + } else { + if (sensor != SENSOR_PO1200) { + cam->cam_mode = vc0323_mode; + cam->nmodes = ARRAY_SIZE(vc0323_mode); + } else { + cam->cam_mode = svga_mode; + cam->nmodes = ARRAY_SIZE(svga_mode); + } + } + + sd->hflip = HFLIP_DEF; + sd->vflip = VFLIP_DEF; + if (sd->sensor == SENSOR_OV7670) { + sd->hflip = 1; + sd->vflip = 1; + } sd->lightfreq = FREQ_DEF; if (sd->sensor != SENSOR_OV7670) gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX); + switch (sd->sensor) { + case SENSOR_OV7660: + case SENSOR_OV7670: + case SENSOR_PO1200: + break; + default: + gspca_dev->ctrl_dis = (1 << HFLIP_IDX) + | (1 << VFLIP_IDX); + break; + } + + sd->sharpness = SHARPNESS_DEF; if (sd->bridge == BRIDGE_VC0321) { reg_r(gspca_dev, 0x8a, 0, 3); @@ -1662,29 +2093,33 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static void setquality(struct gspca_dev *gspca_dev) -{ -#if 0 - struct sd *sd = (struct sd *) gspca_dev; - __u8 quality = 0; - - quality = sd->qindex & 0xff; - reg_w(gspca_dev->dev, 0xa0, quality, 0x0008); -#endif -} - -static void setautogain(struct gspca_dev *gspca_dev) +/* for OV7660 and OV7670 only */ +static void sethvflip(struct gspca_dev *gspca_dev) { -#if 0 struct sd *sd = (struct sd *) gspca_dev; - __u8 autoval; + __u8 data; - if (sd->autogain) - autoval = 0x42; - else - autoval = 0x02; - reg_w(gspca_dev->dev, 0xa0, autoval, 0x0180); -#endif + switch (sd->sensor) { + case SENSOR_OV7660: + data = 1; + break; + case SENSOR_OV7670: + data = 7; + break; + case SENSOR_PO1200: + data = 0; + i2c_write(gspca_dev, 0x03, &data, 1); + data = 0x80 * sd->hflip + | 0x40 * sd->vflip + | 0x06; + i2c_write(gspca_dev, 0x1e, &data, 1); + return; + default: + return; + } + data |= OV7660_MVFP_MIRROR * sd->hflip + | OV7660_MVFP_VFLIP * sd->vflip; + i2c_write(gspca_dev, OV7660_REG_MVFP, &data, 1); } static void setlightfreq(struct gspca_dev *gspca_dev) @@ -1698,6 +2133,20 @@ static void setlightfreq(struct gspca_dev *gspca_dev) usb_exchange(gspca_dev, ov7660_freq_tb[sd->lightfreq]); } +/* po1200 only */ +static void setsharpness(struct gspca_dev *gspca_dev) +{ + struct sd *sd = (struct sd *) gspca_dev; + __u8 data; + + if (sd->sensor != SENSOR_PO1200) + return; + data = 0; + i2c_write(gspca_dev, 0x03, &data, 1); + data = 0xb5 + sd->sharpness * 3; + i2c_write(gspca_dev, 0x61, &data, 1); +} + static int sd_start(struct gspca_dev *gspca_dev) { struct sd *sd = (struct sd *) gspca_dev; @@ -1748,6 +2197,17 @@ static int sd_start(struct gspca_dev *gspca_dev) usb_exchange(gspca_dev, ov7670_initVGA_JPG); } break; + case SENSOR_MI0360: + GammaT = mi1320_gamma; + MatrixT = mi0360_matrix; + if (mode) { + /* 320x240 */ + usb_exchange(gspca_dev, mi0360_initQVGA_JPG); + } else { + /* 640x480 */ + usb_exchange(gspca_dev, mi0360_initVGA_JPG); + } + break; case SENSOR_MI1310_SOC: if (mode) { /* 320x240 */ @@ -1780,6 +2240,11 @@ static int sd_start(struct gspca_dev *gspca_dev) } usb_exchange(gspca_dev, po3130_rundata); break; + case SENSOR_PO1200: + GammaT = po1200_gamma; + MatrixT = po1200_matrix; + usb_exchange(gspca_dev, po1200_initVGA_data); + break; default: PDEBUG(D_PROBE, "Damned !! no sensor found Bye"); return -EMEDIUMTYPE; @@ -1812,11 +2277,16 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(gspca_dev->dev, 0xa0, 0x23, 0xb800); * ISP CTRL_BAS */ /* set the led on 0x0892 0x0896 */ - reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff); - msleep(100); - setquality(gspca_dev); - setautogain(gspca_dev); - setlightfreq(gspca_dev); + if (sd->sensor != SENSOR_PO1200) { + reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff); + msleep(100); + sethvflip(gspca_dev); + setlightfreq(gspca_dev); + } else { + setsharpness(gspca_dev); + sethvflip(gspca_dev); + reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415); + } } return 0; } @@ -1862,24 +2332,48 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, data, len); return; } + + /* The vc0321 sends some additional data after sending the complete + * frame, we ignore this. */ + if (sd->bridge == BRIDGE_VC0321 + && len > frame->v4l2_buf.length - (frame->data_end - frame->data)) + len = frame->v4l2_buf.length - (frame->data_end - frame->data); gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len); } -static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) +static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) { struct sd *sd = (struct sd *) gspca_dev; - sd->autogain = val; + sd->hflip = val; if (gspca_dev->streaming) - setautogain(gspca_dev); + sethvflip(gspca_dev); return 0; } -static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) +static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) { struct sd *sd = (struct sd *) gspca_dev; - *val = sd->autogain; + *val = sd->hflip; + return 0; +} + +static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->vflip = val; + if (gspca_dev->streaming) + sethvflip(gspca_dev); + return 0; +} + +static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->vflip; return 0; } @@ -1901,6 +2395,24 @@ static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val) return 0; } +static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + sd->sharpness = val; + if (gspca_dev->streaming) + setsharpness(gspca_dev); + return 0; +} + +static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val) +{ + struct sd *sd = (struct sd *) gspca_dev; + + *val = sd->sharpness; + return 0; +} + static int sd_querymenu(struct gspca_dev *gspca_dev, struct v4l2_querymenu *menu) { @@ -1940,11 +2452,13 @@ static const struct sd_desc sd_desc = { static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x046d, 0x0892), .driver_info = BRIDGE_VC0321}, {USB_DEVICE(0x046d, 0x0896), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x046d, 0x0897), .driver_info = BRIDGE_VC0321}, {USB_DEVICE(0x0ac8, 0x0321), .driver_info = BRIDGE_VC0321}, {USB_DEVICE(0x0ac8, 0x0323), .driver_info = BRIDGE_VC0323}, {USB_DEVICE(0x0ac8, 0x0328), .driver_info = BRIDGE_VC0321}, {USB_DEVICE(0x0ac8, 0xc001), .driver_info = BRIDGE_VC0321}, {USB_DEVICE(0x0ac8, 0xc002), .driver_info = BRIDGE_VC0321}, + {USB_DEVICE(0x15b8, 0x6002), .driver_info = BRIDGE_VC0323}, {USB_DEVICE(0x17ef, 0x4802), .driver_info = BRIDGE_VC0323}, {} }; diff --git a/linux/drivers/media/video/gspca/zc3xx-reg.h b/linux/drivers/media/video/gspca/zc3xx-reg.h index f52e09c2c..bfb559c3b 100644 --- a/linux/drivers/media/video/gspca/zc3xx-reg.h +++ b/linux/drivers/media/video/gspca/zc3xx-reg.h @@ -244,14 +244,6 @@ #define ZC3XX_R1CA_SHARPNESS04 0x01ca #define ZC3XX_R1CB_SHARPNESS05 0x01cb -/* Synchronization */ -#define ZC3XX_R190_SYNC00LOW 0x0190 -#define ZC3XX_R191_SYNC00MID 0x0191 -#define ZC3XX_R192_SYNC00HIGH 0x0192 -#define ZC3XX_R195_SYNC01LOW 0x0195 -#define ZC3XX_R196_SYNC01MID 0x0196 -#define ZC3XX_R197_SYNC01HIGH 0x0197 - /* Dead pixels */ #define ZC3XX_R250_DEADPIXELSMODE 0x0250 diff --git a/linux/drivers/media/video/gspca/zc3xx.c b/linux/drivers/media/video/gspca/zc3xx.c index adbca6a9d..79d2a776d 100644 --- a/linux/drivers/media/video/gspca/zc3xx.c +++ b/linux/drivers/media/video/gspca/zc3xx.c @@ -51,16 +51,16 @@ struct sd { #define SENSOR_CS2102 0 #define SENSOR_CS2102K 1 #define SENSOR_GC0305 2 -#define SENSOR_HDCS2020 3 -#define SENSOR_HDCS2020b 4 -#define SENSOR_HV7131B 5 -#define SENSOR_HV7131C 6 -#define SENSOR_ICM105A 7 -#define SENSOR_MC501CB 8 -#define SENSOR_OV7620 9 -/*#define SENSOR_OV7648 9 - same values */ -#define SENSOR_OV7630C 10 -#define SENSOR_PAS106 11 +#define SENSOR_HDCS2020b 3 +#define SENSOR_HV7131B 4 +#define SENSOR_HV7131C 5 +#define SENSOR_ICM105A 6 +#define SENSOR_MC501CB 7 +#define SENSOR_OV7620 8 +/*#define SENSOR_OV7648 8 - same values */ +#define SENSOR_OV7630C 9 +#define SENSOR_PAS106 10 +#define SENSOR_PAS202B 11 #define SENSOR_PB0330 12 #define SENSOR_PO2030 13 #define SENSOR_TAS5130CK 14 @@ -173,7 +173,7 @@ static struct ctrl sd_ctrls[] = { }, }; -static struct v4l2_pix_format vga_mode[] = { +static const struct v4l2_pix_format vga_mode[] = { {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 320, .sizeimage = 320 * 240 * 3 / 8 + 590, @@ -186,7 +186,7 @@ static struct v4l2_pix_format vga_mode[] = { .priv = 0}, }; -static struct v4l2_pix_format sif_mode[] = { +static const struct v4l2_pix_format sif_mode[] = { {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, .bytesperline = 176, .sizeimage = 176 * 144 * 3 / 8 + 590, @@ -1653,295 +1653,6 @@ static const struct usb_action gc0305_NoFliker[] = { {} }; -/* play poker with registers at your own risk !! */ -static const struct usb_action hdcs2020xx_Initial[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, - /* D0 ?? E0 did not start */ - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, - {0xa0, 0x08, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, - {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, - {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, - {0xaa, 0x02, 0x0002}, - {0xaa, 0x07, 0x0006}, - {0xaa, 0x08, 0x0002}, - {0xaa, 0x09, 0x0006}, - {0xaa, 0x0a, 0x0001}, - {0xaa, 0x0b, 0x0001}, - {0xaa, 0x0c, 0x0008}, - {0xaa, 0x0d, 0x0000}, - {0xaa, 0x10, 0x0000}, - {0xaa, 0x12, 0x0005}, - {0xaa, 0x13, 0x0063}, - {0xaa, 0x15, 0x0070}, - {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x70, ZC3XX_R18D_YTARGET}, - {0xa1, 0x01, 0x0002}, - {0xa1, 0x01, 0x0008}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - {0xa0, 0x11, ZC3XX_R120_GAMMA00}, /* gamma ~4 */ - {0xa0, 0x37, ZC3XX_R121_GAMMA01}, - {0xa0, 0x58, ZC3XX_R122_GAMMA02}, - {0xa0, 0x79, ZC3XX_R123_GAMMA03}, - {0xa0, 0x91, ZC3XX_R124_GAMMA04}, - {0xa0, 0xa6, ZC3XX_R125_GAMMA05}, - {0xa0, 0xb8, ZC3XX_R126_GAMMA06}, - {0xa0, 0xc7, ZC3XX_R127_GAMMA07}, - {0xa0, 0xd3, ZC3XX_R128_GAMMA08}, - {0xa0, 0xde, ZC3XX_R129_GAMMA09}, - {0xa0, 0xe6, ZC3XX_R12A_GAMMA0A}, - {0xa0, 0xed, ZC3XX_R12B_GAMMA0B}, - {0xa0, 0xf3, ZC3XX_R12C_GAMMA0C}, - {0xa0, 0xf8, ZC3XX_R12D_GAMMA0D}, - {0xa0, 0xfb, ZC3XX_R12E_GAMMA0E}, - {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, - {0xa0, 0x26, ZC3XX_R130_GAMMA10}, - {0xa0, 0x23, ZC3XX_R131_GAMMA11}, - {0xa0, 0x20, ZC3XX_R132_GAMMA12}, - {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, - {0xa0, 0x16, ZC3XX_R134_GAMMA14}, - {0xa0, 0x13, ZC3XX_R135_GAMMA15}, - {0xa0, 0x10, ZC3XX_R136_GAMMA16}, - {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, - {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, - {0xa0, 0x09, ZC3XX_R139_GAMMA19}, - {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, - {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, - {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, - {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, - {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, - {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, - - {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xf5, ZC3XX_R10B_RGB01}, - {0xa0, 0xff, ZC3XX_R10C_RGB02}, - {0xa0, 0xf9, ZC3XX_R10D_RGB10}, - {0xa0, 0x51, ZC3XX_R10E_RGB11}, - {0xa0, 0xf5, ZC3XX_R10F_RGB12}, - {0xa0, 0xfb, ZC3XX_R110_RGB20}, - {0xa0, 0xed, ZC3XX_R111_RGB21}, - {0xa0, 0x5f, ZC3XX_R112_RGB22}, - - {0xa1, 0x01, 0x0180}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, - {0xaa, 0x20, 0x0004}, - {0xaa, 0x21, 0x003d}, - {0xaa, 0x03, 0x0041}, - {0xaa, 0x04, 0x0010}, - {0xaa, 0x05, 0x003d}, - {0xaa, 0x0e, 0x0001}, - {0xaa, 0x0f, 0x0000}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x41, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0195}, - {0xa1, 0x01, 0x0196}, - {0xa1, 0x01, 0x0197}, - {0xa0, 0x3d, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x1d, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x85, ZC3XX_R118_BGAIN}, - {0xa1, 0x01, 0x0116}, - {0xa1, 0x01, 0x0118}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x1d, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x85, ZC3XX_R118_BGAIN}, - {0xa1, 0x01, 0x0116}, - {0xa1, 0x01, 0x0118}, -/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */ - {0xa0, 0x00, 0x0007}, - {} -}; - -static const struct usb_action hdcs2020xx_InitialScale[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, - {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, - {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, - {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, - {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, - {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, - {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, - {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, - {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, - {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, - {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, - {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, - {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, - {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, - {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, - {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, - {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, - {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, - {0xaa, 0x02, 0x0002}, - {0xaa, 0x07, 0x0006}, - {0xaa, 0x08, 0x0002}, - {0xaa, 0x09, 0x0006}, - {0xaa, 0x0a, 0x0001}, - {0xaa, 0x0b, 0x0001}, - {0xaa, 0x0c, 0x0008}, - {0xaa, 0x0d, 0x0000}, - {0xaa, 0x10, 0x0000}, - {0xaa, 0x12, 0x0005}, - {0xaa, 0x13, 0x0063}, - {0xaa, 0x15, 0x0070}, - {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, - {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, - {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, - {0xa0, 0x00, 0x01ad}, - {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, - {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, - {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, - {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, - {0xa0, 0x70, ZC3XX_R18D_YTARGET}, - {0xa1, 0x01, 0x0002}, - {0xa1, 0x01, 0x0008}, - {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */ - {0xa0, 0x04, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */ - {0xa1, 0x01, 0x01c8}, - {0xa1, 0x01, 0x01c9}, - {0xa1, 0x01, 0x01ca}, - {0xa0, 0x07, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */ - {0xa0, 0x11, ZC3XX_R120_GAMMA00}, /* gamma ~4*/ - {0xa0, 0x37, ZC3XX_R121_GAMMA01}, - {0xa0, 0x58, ZC3XX_R122_GAMMA02}, - {0xa0, 0x79, ZC3XX_R123_GAMMA03}, - {0xa0, 0x91, ZC3XX_R124_GAMMA04}, - {0xa0, 0xa6, ZC3XX_R125_GAMMA05}, - {0xa0, 0xb8, ZC3XX_R126_GAMMA06}, - {0xa0, 0xc7, ZC3XX_R127_GAMMA07}, - {0xa0, 0xd3, ZC3XX_R128_GAMMA08}, - {0xa0, 0xde, ZC3XX_R129_GAMMA09}, - {0xa0, 0xe6, ZC3XX_R12A_GAMMA0A}, - {0xa0, 0xed, ZC3XX_R12B_GAMMA0B}, - {0xa0, 0xf3, ZC3XX_R12C_GAMMA0C}, - {0xa0, 0xf8, ZC3XX_R12D_GAMMA0D}, - {0xa0, 0xfb, ZC3XX_R12E_GAMMA0E}, - {0xa0, 0xff, ZC3XX_R12F_GAMMA0F}, - {0xa0, 0x26, ZC3XX_R130_GAMMA10}, - {0xa0, 0x23, ZC3XX_R131_GAMMA11}, - {0xa0, 0x20, ZC3XX_R132_GAMMA12}, - {0xa0, 0x1c, ZC3XX_R133_GAMMA13}, - {0xa0, 0x16, ZC3XX_R134_GAMMA14}, - {0xa0, 0x13, ZC3XX_R135_GAMMA15}, - {0xa0, 0x10, ZC3XX_R136_GAMMA16}, - {0xa0, 0x0d, ZC3XX_R137_GAMMA17}, - {0xa0, 0x0b, ZC3XX_R138_GAMMA18}, - {0xa0, 0x09, ZC3XX_R139_GAMMA19}, - {0xa0, 0x07, ZC3XX_R13A_GAMMA1A}, - {0xa0, 0x06, ZC3XX_R13B_GAMMA1B}, - {0xa0, 0x05, ZC3XX_R13C_GAMMA1C}, - {0xa0, 0x04, ZC3XX_R13D_GAMMA1D}, - {0xa0, 0x03, ZC3XX_R13E_GAMMA1E}, - {0xa0, 0x02, ZC3XX_R13F_GAMMA1F}, - {0xa0, 0x60, ZC3XX_R10A_RGB00}, /* matrix */ - {0xa0, 0xff, ZC3XX_R10B_RGB01}, - {0xa0, 0xff, ZC3XX_R10C_RGB02}, - {0xa0, 0xff, ZC3XX_R10D_RGB10}, - {0xa0, 0x60, ZC3XX_R10E_RGB11}, - {0xa0, 0xff, ZC3XX_R10F_RGB12}, - {0xa0, 0xff, ZC3XX_R110_RGB20}, - {0xa0, 0xff, ZC3XX_R111_RGB21}, - {0xa0, 0x60, ZC3XX_R112_RGB22}, - - {0xa1, 0x01, 0x0180}, - {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, - {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, - {0xaa, 0x20, 0x0002}, - {0xaa, 0x21, 0x001b}, - {0xaa, 0x03, 0x0044}, - {0xaa, 0x04, 0x0008}, - {0xaa, 0x05, 0x001b}, - {0xaa, 0x0e, 0x0001}, - {0xaa, 0x0f, 0x0000}, - {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, - {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, - {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, - {0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW}, - {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, - {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, - {0xa0, 0x44, ZC3XX_R01D_HSYNC_0}, - {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, - {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, - {0xa0, 0xeb, ZC3XX_R020_HSYNC_3}, - {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, - {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, - {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa1, 0x01, 0x0195}, - {0xa1, 0x01, 0x0196}, - {0xa1, 0x01, 0x0197}, - {0xa0, 0x1b, ZC3XX_R192_EXPOSURELIMITLOW}, - {0xa0, 0x02, ZC3XX_R191_EXPOSURELIMITMID}, - {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, - {0xa0, 0x1d, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x99, ZC3XX_R118_BGAIN}, - {0xa1, 0x01, 0x0116}, - {0xa1, 0x01, 0x0118}, - {0xa1, 0x01, 0x0180}, - {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, - {0xa0, 0x1d, ZC3XX_R116_RGAIN}, - {0xa0, 0x40, ZC3XX_R117_GGAIN}, - {0xa0, 0x99, ZC3XX_R118_BGAIN}, -/* {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, */ - {0xa0, 0x00, 0x0007}, -/* {0xa0, 0x18, 0x00fe}, */ - {} -}; static const struct usb_action hdcs2020xb_Initial[] = { {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, {0xa0, 0x11, ZC3XX_R002_CLOCKSELECT}, @@ -2368,12 +2079,12 @@ static const struct usb_action hv7131b_50HZ[] = { /* 640x480*/ {0xaa, 0x21, 0x0050}, /* 00,21,50,aa */ {0xaa, 0x22, 0x001b}, /* 00,22,1b,aa */ {0xaa, 0x23, 0x00fc}, /* 00,23,fc,aa */ - {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ - {0xa0, 0x9b, ZC3XX_R191_SYNC00MID}, /* 01,91,9b,cc */ - {0xa0, 0x80, ZC3XX_R192_SYNC00HIGH}, /* 01,92,80,cc */ - {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ - {0xa0, 0xea, ZC3XX_R196_SYNC01MID}, /* 01,96,ea,cc */ - {0xa0, 0x60, ZC3XX_R197_SYNC01HIGH}, /* 01,97,60,cc */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0x9b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,9b,cc */ + {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0xea, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,ea,cc */ + {0xa0, 0x60, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,60,cc */ {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ @@ -2393,12 +2104,12 @@ static const struct usb_action hv7131b_50HZScale[] = { /* 320x240 */ {0xaa, 0x21, 0x0050}, /* 00,21,50,aa */ {0xaa, 0x22, 0x0012}, /* 00,22,12,aa */ {0xaa, 0x23, 0x0080}, /* 00,23,80,aa */ - {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ - {0xa0, 0x9b, ZC3XX_R191_SYNC00MID}, /* 01,91,9b,cc */ - {0xa0, 0x80, ZC3XX_R192_SYNC00HIGH}, /* 01,92,80,cc */ - {0xa0, 0x01, ZC3XX_R195_SYNC01LOW}, /* 01,95,01,cc */ - {0xa0, 0xd4, ZC3XX_R196_SYNC01MID}, /* 01,96,d4,cc */ - {0xa0, 0xc0, ZC3XX_R197_SYNC01HIGH}, /* 01,97,c0,cc */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0x9b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,9b,cc */ + {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,80,cc */ + {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,01,cc */ + {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,d4,cc */ + {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,c0,cc */ {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */ {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */ {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ @@ -2418,12 +2129,12 @@ static const struct usb_action hv7131b_60HZ[] = { /* 640x480*/ {0xaa, 0x21, 0x0040}, /* 00,21,40,aa */ {0xaa, 0x22, 0x0013}, /* 00,22,13,aa */ {0xaa, 0x23, 0x004c}, /* 00,23,4c,aa */ - {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ - {0xa0, 0x4d, ZC3XX_R191_SYNC00MID}, /* 01,91,4d,cc */ - {0xa0, 0x60, ZC3XX_R192_SYNC00HIGH}, /* 01,92,60,cc */ - {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ - {0xa0, 0xc3, ZC3XX_R196_SYNC01MID}, /* 01,96,c3,cc */ - {0xa0, 0x50, ZC3XX_R197_SYNC01HIGH}, /* 01,97,50,cc */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0x4d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,4d,cc */ + {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,60,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,c3,cc */ + {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,50,cc */ {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0c,cc */ {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,18,cc */ {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ @@ -2443,12 +2154,12 @@ static const struct usb_action hv7131b_60HZScale[] = { /* 320x240 */ {0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */ {0xaa, 0x22, 0x0016}, /* 00,22,16,aa */ {0xaa, 0x23, 0x0040}, /* 00,23,40,aa */ - {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ - {0xa0, 0x4d, ZC3XX_R191_SYNC00MID}, /* 01,91,4d,cc */ - {0xa0, 0x60, ZC3XX_R192_SYNC00HIGH}, /* 01,92,60,cc */ - {0xa0, 0x01, ZC3XX_R195_SYNC01LOW}, /* 01,95,01,cc */ - {0xa0, 0x86, ZC3XX_R196_SYNC01MID}, /* 01,96,86,cc */ - {0xa0, 0xa0, ZC3XX_R197_SYNC01HIGH}, /* 01,97,a0,cc */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0x4d, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,4d,cc */ + {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,60,cc */ + {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,01,cc */ + {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,86,cc */ + {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,a0,cc */ {0xa0, 0x07, ZC3XX_R18C_AEFREEZE}, /* 01,8c,07,cc */ {0xa0, 0x0f, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,0f,cc */ {0xa0, 0x18, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,18,cc */ @@ -2468,12 +2179,12 @@ static const struct usb_action hv7131b_NoFliker[] = { /* 640x480*/ {0xaa, 0x21, 0x0010}, /* 00,21,10,aa */ {0xaa, 0x22, 0x0000}, /* 00,22,00,aa */ {0xaa, 0x23, 0x0003}, /* 00,23,03,aa */ - {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ - {0xa0, 0xf8, ZC3XX_R191_SYNC00MID}, /* 01,91,f8,cc */ - {0xa0, 0x00, ZC3XX_R192_SYNC00HIGH}, /* 01,92,00,cc */ - {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ - {0xa0, 0x02, ZC3XX_R196_SYNC01MID}, /* 01,96,02,cc */ - {0xa0, 0x00, ZC3XX_R197_SYNC01HIGH}, /* 01,97,00,cc */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,f8,cc */ + {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,00,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,02,cc */ + {0xa0, 0x00, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,00,cc */ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ @@ -2493,12 +2204,12 @@ static const struct usb_action hv7131b_NoFlikerScale[] = { /* 320x240 */ {0xaa, 0x21, 0x00a0}, /* 00,21,a0,aa */ {0xaa, 0x22, 0x0016}, /* 00,22,16,aa */ {0xaa, 0x23, 0x0040}, /* 00,23,40,aa */ - {0xa0, 0x2f, ZC3XX_R190_SYNC00LOW}, /* 01,90,2f,cc */ - {0xa0, 0xf8, ZC3XX_R191_SYNC00MID}, /* 01,91,f8,cc */ - {0xa0, 0x00, ZC3XX_R192_SYNC00HIGH}, /* 01,92,00,cc */ - {0xa0, 0x00, ZC3XX_R195_SYNC01LOW}, /* 01,95,00,cc */ - {0xa0, 0x02, ZC3XX_R196_SYNC01MID}, /* 01,96,02,cc */ - {0xa0, 0x00, ZC3XX_R197_SYNC01HIGH}, /* 01,97,00,cc */ + {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,2f,cc */ + {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,f8,cc */ + {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,00,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,02,cc */ + {0xa0, 0x00, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,00,cc */ {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ @@ -4424,6 +4135,270 @@ static const struct usb_action pas106b_NoFliker[] = { {} }; +/* from usbvm31b.inf */ +static const struct usb_action pas202b_Initial[] = { /* 640x480 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */ + {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0e,cc */ + {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,e0,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ + {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,00,cc */ + {0xa0, 0x03, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,03,cc */ + {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,00,cc */ + {0xa0, 0x03, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,03,cc */ + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ + {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,e6,cc */ + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ + {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,86,cc */ + {0xaa, 0x02, 0x0002}, /* 00,02,04,aa --> 02 */ + {0xaa, 0x07, 0x0006}, /* 00,07,06,aa */ + {0xaa, 0x08, 0x0002}, /* 00,08,02,aa */ + {0xaa, 0x09, 0x0006}, /* 00,09,06,aa */ + {0xaa, 0x0a, 0x0001}, /* 00,0a,01,aa */ + {0xaa, 0x0b, 0x0001}, /* 00,0b,01,aa */ + {0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */ + {0xaa, 0x0d, 0x0000}, /* 00,0d,00,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x12, 0x0005}, /* 00,12,05,aa */ + {0xaa, 0x13, 0x0063}, /* 00,13,63,aa */ + {0xaa, 0x15, 0x0070}, /* 00,15,70,aa */ + {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, /* 01,8d,70,cc */ + {} +}; +static const struct usb_action pas202b_InitialScale[] = { /* 320x240 */ + {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */ + {0xa0, 0x00, ZC3XX_R008_CLOCKSETTING}, /* 00,08,00,cc */ + {0xa0, 0x0e, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,0e,cc */ + {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */ + {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc */ + {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc */ + {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc */ + {0xa0, 0xd0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 00,06,d0,cc */ + {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING}, /* 00,01,01,cc */ + {0xa0, 0x03, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,03,cc */ + {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,01,cc */ + {0xa0, 0x08, ZC3XX_R08D_COMPABILITYMODE}, /* 00,8d,08,cc */ + {0xa0, 0x08, ZC3XX_R098_WINYSTARTLOW}, /* 00,98,08,cc */ + {0xa0, 0x02, ZC3XX_R09A_WINXSTARTLOW}, /* 00,9a,02,cc */ + {0xa0, 0x08, ZC3XX_R11A_FIRSTYLOW}, /* 01,1a,08,cc */ + {0xa0, 0x02, ZC3XX_R11C_FIRSTXLOW}, /* 01,1c,02,cc */ + {0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH}, /* 00,9b,01,cc */ + {0xa0, 0xd8, ZC3XX_R09C_WINHEIGHTLOW}, /* 00,9c,d8,cc */ + {0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH}, /* 00,9d,02,cc */ + {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW}, /* 00,9e,88,cc */ + {0xaa, 0x02, 0x0002}, /* 00,02,02,aa */ + {0xaa, 0x07, 0x0006}, /* 00,07,06,aa */ + {0xaa, 0x08, 0x0002}, /* 00,08,02,aa */ + {0xaa, 0x09, 0x0006}, /* 00,09,06,aa */ + {0xaa, 0x0a, 0x0001}, /* 00,0a,01,aa */ + {0xaa, 0x0b, 0x0001}, /* 00,0b,01,aa */ + {0xaa, 0x0c, 0x0008}, /* 00,0c,08,aa */ + {0xaa, 0x0d, 0x0000}, /* 00,0d,00,aa */ + {0xaa, 0x10, 0x0000}, /* 00,10,00,aa */ + {0xaa, 0x12, 0x0005}, /* 00,12,05,aa */ + {0xaa, 0x13, 0x0063}, /* 00,13,63,aa */ + {0xaa, 0x15, 0x0070}, /* 00,15,70,aa */ + {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,37,cc */ + {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc */ + {0xa0, 0x06, ZC3XX_R189_AWBSTATUS}, /* 01,89,06,cc */ + {0xa0, 0x00, 0x01ad}, /* 01,ad,00,cc */ + {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE}, /* 01,c5,03,cc */ + {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc */ + {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc */ + {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc */ + {0xa0, 0x70, ZC3XX_R18D_YTARGET}, /* 01,8d,70,cc */ + {} +}; +static const struct usb_action pas202b_50HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ + {0xaa, 0x21, 0x0068}, /* 00,21,68,aa */ + {0xaa, 0x03, 0x0044}, /* 00,03,44,aa */ + {0xaa, 0x04, 0x0009}, /* 00,04,09,aa */ + {0xaa, 0x05, 0x0028}, /* 00,05,28,aa */ + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */ + {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,d2,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x4d, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,4d,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x44, ZC3XX_R01D_HSYNC_0}, /* 00,1d,44,cc */ + {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */ + {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ad,cc */ + {0xa0, 0xeb, ZC3XX_R020_HSYNC_3}, /* 00,20,eb,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; +static const struct usb_action pas202b_50HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ + {0xaa, 0x21, 0x006c}, /* 00,21,6c,aa */ + {0xaa, 0x03, 0x0041}, /* 00,03,41,aa */ + {0xaa, 0x04, 0x0009}, /* 00,04,09,aa */ + {0xaa, 0x05, 0x002c}, /* 00,05,2c,aa */ + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0f,cc */ + {0xa0, 0xbe, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,be,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x9b, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,9b,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x41, ZC3XX_R01D_HSYNC_0}, /* 00,1d,41,cc */ + {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */ + {0xa0, 0xad, ZC3XX_R01F_HSYNC_2}, /* 00,1f,ad,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; +static const struct usb_action pas202b_60HZ[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ + {0xaa, 0x21, 0x0000}, /* 00,21,00,aa */ + {0xaa, 0x03, 0x0045}, /* 00,03,45,aa */ + {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */ + {0xaa, 0x05, 0x0000}, /* 00,05,00,aa */ + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */ + {0xa0, 0xc0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,c0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x40, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,40,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x45, ZC3XX_R01D_HSYNC_0}, /* 00,1d,45,cc */ + {0xa0, 0x8e, ZC3XX_R01E_HSYNC_1}, /* 00,1e,8e,cc */ + {0xa0, 0xc1, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c1,cc */ + {0xa0, 0xf5, ZC3XX_R020_HSYNC_3}, /* 00,20,f5,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; +static const struct usb_action pas202b_60HZScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ + {0xaa, 0x21, 0x0004}, /* 00,21,04,aa */ + {0xaa, 0x03, 0x0042}, /* 00,03,42,aa */ + {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */ + {0xaa, 0x05, 0x0004}, /* 00,05,04,aa */ + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,14,cc */ + {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0f,cc */ + {0xa0, 0x9f, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,9f,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,81,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x42, ZC3XX_R01D_HSYNC_0}, /* 00,1d,42,cc */ + {0xa0, 0x6f, ZC3XX_R01E_HSYNC_1}, /* 00,1e,6f,cc */ + {0xa0, 0xaf, ZC3XX_R01F_HSYNC_2}, /* 00,1f,af,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; +static const struct usb_action pas202b_NoFliker[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ + {0xaa, 0x21, 0x0020}, /* 00,21,20,aa */ + {0xaa, 0x03, 0x0040}, /* 00,03,40,aa */ + {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */ + {0xaa, 0x05, 0x0020}, /* 00,05,20,aa */ + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,07,cc */ + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x02, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,02,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x40, ZC3XX_R01D_HSYNC_0}, /* 00,1d,40,cc */ + {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, /* 00,1e,60,cc */ + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; +static const struct usb_action pas202b_NoFlikerScale[] = { + {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */ + {0xa0, 0x20, ZC3XX_R087_EXPTIMEMID}, /* 00,87,20,cc */ + {0xa0, 0x21, ZC3XX_R088_EXPTIMELOW}, /* 00,88,21,cc */ + {0xaa, 0x20, 0x0002}, /* 00,20,02,aa */ + {0xaa, 0x21, 0x0010}, /* 00,21,10,aa */ + {0xaa, 0x03, 0x0040}, /* 00,03,40,aa */ + {0xaa, 0x04, 0x0008}, /* 00,04,08,aa */ + {0xaa, 0x05, 0x0010}, /* 00,05,10,aa */ + {0xaa, 0x0e, 0x0001}, /* 00,0e,01,aa */ + {0xaa, 0x0f, 0x0000}, /* 00,0f,00,aa */ + {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc */ + {0xa0, 0x0f, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0f,cc */ + {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,f0,cc */ + {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc */ + {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */ + {0xa0, 0x02, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,02,cc */ + {0xa0, 0x10, ZC3XX_R18C_AEFREEZE}, /* 01,8c,10,cc */ + {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,20,cc */ + {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,00,cc */ + {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,00,cc */ + {0xa0, 0x40, ZC3XX_R01D_HSYNC_0}, /* 00,1d,40,cc */ + {0xa0, 0x60, ZC3XX_R01E_HSYNC_1}, /* 00,1e,60,cc */ + {0xa0, 0x90, ZC3XX_R01F_HSYNC_2}, /* 00,1f,90,cc */ + {0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc */ + {0xa0, 0x0f, ZC3XX_R087_EXPTIMEMID}, /* 00,87,0f,cc */ + {0xa0, 0x0e, ZC3XX_R088_EXPTIMELOW}, /* 00,88,0e,cc */ + {} +}; + static const struct usb_action pb03303x_Initial[] = { {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, @@ -5760,7 +5735,7 @@ static const struct usb_action tas5130cxx_Initial[] = { {} }; static const struct usb_action tas5130cxx_InitialScale[] = { - {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, +/*?? {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, */ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, {0xa0, 0x40, ZC3XX_R002_CLOCKSELECT}, @@ -6084,7 +6059,7 @@ static const struct usb_action tas5130c_vf0250_InitialScale[] = { {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */ {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */ {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */ - {0xaa, 0x01, 0x0000}, +/*?? {0xaa, 0x01, 0x0000}, */ {0xaa, 0x01, 0x0000}, {0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */ {0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */ @@ -6100,8 +6075,8 @@ static const struct usb_action tas5130c_vf0250_InitialScale[] = { {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */ {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */ {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */ - {0xa0, 0x00, 0x0039}, - {0xa1, 0x01, 0x0037}, +/*?? {0xa0, 0x00, 0x0039}, + {0xa1, 0x01, 0x0037}, */ {0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */ {0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa (e6 -> e8) */ {0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */ @@ -6338,7 +6313,7 @@ static __u8 i2c_write(struct gspca_dev *gspca_dev, reg_w_i(gspca_dev->dev, valL, 0x93); reg_w_i(gspca_dev->dev, valH, 0x94); reg_w_i(gspca_dev->dev, 0x01, 0x90); /* <- write command */ - msleep(5); + msleep(15); retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */ PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)", reg, valH, valL, retbyte); @@ -6381,31 +6356,35 @@ static void setmatrix(struct gspca_dev *gspca_dev) {0x50, 0xf8, 0xf8, 0xf8, 0x50, 0xf8, 0xf8, 0xf8, 0x50}; static const __u8 ov7620_matrix[9] = {0x58, 0xf4, 0xf4, 0xf4, 0x58, 0xf4, 0xf4, 0xf4, 0x58}; + static const __u8 pas202b_matrix[9] = + {0x4c, 0xf5, 0xff, 0xf9, 0x51, 0xf5, 0xfb, 0xed, 0x5f}; static const __u8 po2030_matrix[9] = {0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60}; static const __u8 vf0250_matrix[9] = {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b}; + static const __u8 *matrix_tb[SENSOR_MAX] = { + NULL, /* SENSOR_CS2102 0 */ + NULL, /* SENSOR_CS2102K 1 */ + gc0305_matrix, /* SENSOR_GC0305 2 */ + NULL, /* SENSOR_HDCS2020b 3 */ + NULL, /* SENSOR_HV7131B 4 */ + NULL, /* SENSOR_HV7131C 5 */ + NULL, /* SENSOR_ICM105A 6 */ + NULL, /* SENSOR_MC501CB 7 */ + ov7620_matrix, /* SENSOR_OV7620 8 */ + NULL, /* SENSOR_OV7630C 9 */ + NULL, /* SENSOR_PAS106 10 */ + pas202b_matrix, /* SENSOR_PAS202B 11 */ + NULL, /* SENSOR_PB0330 12 */ + po2030_matrix, /* SENSOR_PO2030 13 */ + NULL, /* SENSOR_TAS5130CK 14 */ + NULL, /* SENSOR_TAS5130CXX 15 */ + vf0250_matrix, /* SENSOR_TAS5130C_VF0250 16 */ + }; - switch (sd->sensor) { - case SENSOR_GC0305: - case SENSOR_HV7131B: - matrix = gc0305_matrix; - break; - case SENSOR_MC501CB: - return; /* no matrix? */ - case SENSOR_OV7620: -/* case SENSOR_OV7648: */ - matrix = ov7620_matrix; - break; - case SENSOR_PO2030: - matrix = po2030_matrix; - break; - case SENSOR_TAS5130C_VF0250: - matrix = vf0250_matrix; - break; - default: /* matrix already loaded */ - return; - } + matrix = matrix_tb[sd->sensor]; + if (matrix == NULL) + return; /* matrix already loaded */ for (i = 0; i < ARRAY_SIZE(ov7620_matrix); i++) reg_w(gspca_dev->dev, matrix[i], 0x010a + i); } @@ -6621,42 +6600,42 @@ static int setlightfreq(struct gspca_dev *gspca_dev) {gc0305_NoFliker, gc0305_NoFliker, gc0305_50HZ, gc0305_50HZ, gc0305_60HZ, gc0305_60HZ}, -/* SENSOR_HDCS2020 3 */ - {NULL, NULL, - NULL, NULL, - NULL, NULL}, -/* SENSOR_HDCS2020b 4 */ +/* SENSOR_HDCS2020b 3 */ {hdcs2020b_NoFliker, hdcs2020b_NoFliker, hdcs2020b_50HZ, hdcs2020b_50HZ, hdcs2020b_60HZ, hdcs2020b_60HZ}, -/* SENSOR_HV7131B 5 */ +/* SENSOR_HV7131B 4 */ {hv7131b_NoFlikerScale, hv7131b_NoFliker, hv7131b_50HZScale, hv7131b_50HZ, hv7131b_60HZScale, hv7131b_60HZ}, -/* SENSOR_HV7131C 6 */ +/* SENSOR_HV7131C 5 */ {NULL, NULL, NULL, NULL, NULL, NULL}, -/* SENSOR_ICM105A 7 */ +/* SENSOR_ICM105A 6 */ {icm105a_NoFliker, icm105a_NoFlikerScale, icm105a_50HZ, icm105a_50HZScale, icm105a_60HZ, icm105a_60HZScale}, -/* SENSOR_MC501CB 8 */ +/* SENSOR_MC501CB 7 */ {MC501CB_NoFliker, MC501CB_NoFlikerScale, MC501CB_50HZ, MC501CB_50HZScale, MC501CB_60HZ, MC501CB_60HZScale}, -/* SENSOR_OV7620 9 */ +/* SENSOR_OV7620 8 */ {OV7620_NoFliker, OV7620_NoFliker, OV7620_50HZ, OV7620_50HZ, OV7620_60HZ, OV7620_60HZ}, -/* SENSOR_OV7630C 10 */ +/* SENSOR_OV7630C 9 */ {NULL, NULL, NULL, NULL, NULL, NULL}, -/* SENSOR_PAS106 11 */ +/* SENSOR_PAS106 10 */ {pas106b_NoFliker, pas106b_NoFliker, pas106b_50HZ, pas106b_50HZ, pas106b_60HZ, pas106b_60HZ}, +/* SENSOR_PAS202B 11 */ + {pas202b_NoFlikerScale, pas202b_NoFliker, + pas202b_50HZScale, pas202b_50HZ, + pas202b_60HZScale, pas202b_60HZ}, /* SENSOR_PB0330 12 */ {pb0330_NoFliker, pb0330_NoFlikerScale, pb0330_50HZ, pb0330_50HZScale, @@ -7038,15 +7017,15 @@ static int sd_config(struct gspca_dev *gspca_dev, 5, /* SENSOR_CS2102 0 */ 5, /* SENSOR_CS2102K 1 */ 4, /* SENSOR_GC0305 2 */ - 4, /* SENSOR_HDCS2020 3 */ - 4, /* SENSOR_HDCS2020b 4 */ - 4, /* SENSOR_HV7131B 5 */ - 4, /* SENSOR_HV7131C 6 */ - 4, /* SENSOR_ICM105A 7 */ - 4, /* SENSOR_MC501CB 8 */ - 3, /* SENSOR_OV7620 9 */ - 4, /* SENSOR_OV7630C 10 */ - 4, /* SENSOR_PAS106 11 */ + 4, /* SENSOR_HDCS2020b 3 */ + 4, /* SENSOR_HV7131B 4 */ + 4, /* SENSOR_HV7131C 5 */ + 4, /* SENSOR_ICM105A 6 */ + 4, /* SENSOR_MC501CB 7 */ + 3, /* SENSOR_OV7620 8 */ + 4, /* SENSOR_OV7630C 9 */ + 4, /* SENSOR_PAS106 10 */ + 4, /* SENSOR_PAS202B 11 */ 4, /* SENSOR_PB0330 12 */ 4, /* SENSOR_PO2030 13 */ 4, /* SENSOR_TAS5130CK 14 */ @@ -7102,8 +7081,8 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->sensor = SENSOR_ICM105A; break; case 0x0e: - PDEBUG(D_PROBE, "Find Sensor HDCS2020"); - sd->sensor = SENSOR_HDCS2020; + PDEBUG(D_PROBE, "Find Sensor PAS202B"); + sd->sensor = SENSOR_PAS202B; sd->sharpness = 1; break; case 0x0f: @@ -7196,7 +7175,6 @@ static int sd_config(struct gspca_dev *gspca_dev, case SENSOR_PO2030: gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX); break; - case SENSOR_HDCS2020: case SENSOR_HV7131B: case SENSOR_HV7131C: case SENSOR_OV7630C: @@ -7226,15 +7204,15 @@ static int sd_start(struct gspca_dev *gspca_dev) {cs2102_InitialScale, cs2102_Initial}, /* 0 */ {cs2102K_InitialScale, cs2102K_Initial}, /* 1 */ {gc0305_Initial, gc0305_InitialScale}, /* 2 */ - {hdcs2020xx_InitialScale, hdcs2020xx_Initial}, /* 3 */ - {hdcs2020xb_InitialScale, hdcs2020xb_Initial}, /* 4 */ - {hv7131bxx_InitialScale, hv7131bxx_Initial}, /* 5 */ - {hv7131cxx_InitialScale, hv7131cxx_Initial}, /* 6 */ - {icm105axx_InitialScale, icm105axx_Initial}, /* 7 */ - {MC501CB_InitialScale, MC501CB_Initial}, /* 9 */ - {OV7620_mode0, OV7620_mode1}, /* 9 */ - {ov7630c_InitialScale, ov7630c_Initial}, /* 10 */ - {pas106b_InitialScale, pas106b_Initial}, /* 11 */ + {hdcs2020xb_InitialScale, hdcs2020xb_Initial}, /* 3 */ + {hv7131bxx_InitialScale, hv7131bxx_Initial}, /* 4 */ + {hv7131cxx_InitialScale, hv7131cxx_Initial}, /* 5 */ + {icm105axx_InitialScale, icm105axx_Initial}, /* 6 */ + {MC501CB_InitialScale, MC501CB_Initial}, /* 7 */ + {OV7620_mode0, OV7620_mode1}, /* 8 */ + {ov7630c_InitialScale, ov7630c_Initial}, /* 9 */ + {pas106b_InitialScale, pas106b_Initial}, /* 10 */ + {pas202b_Initial, pas202b_InitialScale}, /* 11 */ {pb0330xx_InitialScale, pb0330xx_Initial}, /* 12 */ /* or {pb03303x_InitialScale, pb03303x_Initial}, */ {PO2030_mode0, PO2030_mode1}, /* 13 */ @@ -7291,6 +7269,11 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_r(gspca_dev, 0x0008); reg_w(dev, 0x00, 0x0008); break; + case SENSOR_PAS202B: +#if 0/*fixme*/ + reg_r(gspca_dev, ZC3XX_R002_CLOCKSELECT); + /* fall thru */ +#endif case SENSOR_GC0305: reg_r(gspca_dev, 0x0008); /* fall thru */ @@ -7304,7 +7287,6 @@ static int sd_start(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_CS2102: /* gamma set in xxx_Initial */ case SENSOR_CS2102K: - case SENSOR_HDCS2020: case SENSOR_HDCS2020b: case SENSOR_PB0330: /* pb with chip_revision - see above */ case SENSOR_OV7630C: @@ -7317,6 +7299,7 @@ static int sd_start(struct gspca_dev *gspca_dev) setmatrix(gspca_dev); /* one more time? */ switch (sd->sensor) { case SENSOR_OV7620: + case SENSOR_PAS202B: reg_r(gspca_dev, 0x0180); /* from win */ reg_w(dev, 0x00, 0x0180); break; @@ -7328,37 +7311,29 @@ static int sd_start(struct gspca_dev *gspca_dev) switch (sd->sensor) { case SENSOR_GC0305: - case SENSOR_OV7620: reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ reg_w(dev, 0x15, 0x01ae); - sd->autogain = 0; - break; + /* fall thru */ + case SENSOR_PAS202B: case SENSOR_PO2030: - reg_w(dev, 0x40, 0x0117); /* (from win traces) */ +/* reg_w(dev, 0x40, ZC3XX_R117_GGAIN); * (from win traces) */ reg_r(gspca_dev, 0x0180); break; - } - - setautogain(gspca_dev); - switch (sd->sensor) { - case SENSOR_GC0305: -/* setlightfreq(gspca_dev); ?? (end: 80 -> [18d]) */ - reg_w(dev, 0x09, 0x01ad); /* (from win traces) */ - reg_w(dev, 0x15, 0x01ae); - reg_w(dev, 0x40, 0x0180); - reg_w(dev, 0x40, 0x0117); - reg_r(gspca_dev, 0x0180); - sd->autogain = 1; - setautogain(gspca_dev); - break; case SENSOR_OV7620: + reg_w(dev, 0x09, 0x01ad); + reg_w(dev, 0x15, 0x01ae); i2c_read(gspca_dev, 0x13); /*fixme: returns 0xa3 */ i2c_write(gspca_dev, 0x13, 0xa3, 0x00); /*fixme: returned value to send? */ - reg_w(dev, 0x40, 0x0117); /* (from win traces) */ + reg_w(dev, 0x40, 0x0117); reg_r(gspca_dev, 0x0180); - setautogain(gspca_dev); - msleep(500); + break; + } + + setautogain(gspca_dev); + switch (sd->sensor) { + case SENSOR_PAS202B: + reg_w(dev, 0x00, 0x0007); /* (from win traces) */ break; case SENSOR_PO2030: msleep(500); @@ -7368,6 +7343,8 @@ static int sd_start(struct gspca_dev *gspca_dev) reg_w(dev, 0x02, 0x0008); break; } + if (sd->sensor == SENSOR_PAS202B) + reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING); return 0; } @@ -7565,6 +7542,7 @@ static const __devinitdata struct usb_device_id device_table[] = { {USB_DEVICE(0x0458, 0x700c)}, {USB_DEVICE(0x0458, 0x700f)}, {USB_DEVICE(0x0461, 0x0a00)}, + {USB_DEVICE(0x046d, 0x089d), .driver_info = SENSOR_MC501CB}, {USB_DEVICE(0x046d, 0x08a0)}, {USB_DEVICE(0x046d, 0x08a1)}, {USB_DEVICE(0x046d, 0x08a2)}, |