summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/gspca
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/gspca')
-rw-r--r--linux/drivers/media/video/gspca/Kconfig9
-rw-r--r--linux/drivers/media/video/gspca/Makefile2
-rw-r--r--linux/drivers/media/video/gspca/conex.c54
-rw-r--r--linux/drivers/media/video/gspca/finepix.c422
-rw-r--r--linux/drivers/media/video/gspca/gspca.c82
-rw-r--r--linux/drivers/media/video/gspca/gspca.h6
-rw-r--r--linux/drivers/media/video/gspca/jpeg.h250
-rw-r--r--linux/drivers/media/video/gspca/m5602/Makefile2
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_bridge.h34
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_core.c76
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c479
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h862
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_ov7660.c227
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_ov7660.h279
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_ov9650.c709
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_ov9650.h292
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_po1030.c604
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_po1030.h539
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c512
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h179
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c519
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h366
-rw-r--r--linux/drivers/media/video/gspca/m5602/m5602_sensor.h20
-rw-r--r--linux/drivers/media/video/gspca/mars.c56
-rw-r--r--linux/drivers/media/video/gspca/mr97310a.c30
-rw-r--r--linux/drivers/media/video/gspca/ov534.c957
-rw-r--r--linux/drivers/media/video/gspca/sonixb.c2
-rw-r--r--linux/drivers/media/video/gspca/sonixj.c205
-rw-r--r--linux/drivers/media/video/gspca/spca500.c88
-rw-r--r--linux/drivers/media/video/gspca/spca508.c1947
-rw-r--r--linux/drivers/media/video/gspca/spca561.c105
-rw-r--r--linux/drivers/media/video/gspca/sq905.c37
-rw-r--r--linux/drivers/media/video/gspca/sq905c.c329
-rw-r--r--linux/drivers/media/video/gspca/stk014.c58
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c76
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h10
-rw-r--r--linux/drivers/media/video/gspca/sunplus.c88
-rw-r--r--linux/drivers/media/video/gspca/t613.c8
-rw-r--r--linux/drivers/media/video/gspca/vc032x.c956
-rw-r--r--linux/drivers/media/video/gspca/zc3xx.c75
40 files changed, 6953 insertions, 4598 deletions
diff --git a/linux/drivers/media/video/gspca/Kconfig b/linux/drivers/media/video/gspca/Kconfig
index a0f05ef5c..578dc4ffc 100644
--- a/linux/drivers/media/video/gspca/Kconfig
+++ b/linux/drivers/media/video/gspca/Kconfig
@@ -185,6 +185,15 @@ config USB_GSPCA_SQ905
To compile this driver as a module, choose M here: the
module will be called gspca_sq905.
+config USB_GSPCA_SQ905C
+ tristate "SQ Technologies SQ905C based USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SQ905C chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sq905c.
+
config USB_GSPCA_STK014
tristate "Syntek DV4000 (STK014) USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/linux/drivers/media/video/gspca/Makefile b/linux/drivers/media/video/gspca/Makefile
index b6ec61185..8a6643e8e 100644
--- a/linux/drivers/media/video/gspca/Makefile
+++ b/linux/drivers/media/video/gspca/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o
obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o
obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o
obj-$(CONFIG_USB_GSPCA_SQ905) += gspca_sq905.o
+obj-$(CONFIG_USB_GSPCA_SQ905C) += gspca_sq905c.o
obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o
obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o
obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o
@@ -43,6 +44,7 @@ gspca_spca506-objs := spca506.o
gspca_spca508-objs := spca508.o
gspca_spca561-objs := spca561.o
gspca_sq905-objs := sq905.o
+gspca_sq905c-objs := sq905c.o
gspca_stk014-objs := stk014.o
gspca_sunplus-objs := sunplus.o
gspca_t613-objs := t613.o
diff --git a/linux/drivers/media/video/gspca/conex.c b/linux/drivers/media/video/gspca/conex.c
index de2e608bf..219cfa6fb 100644
--- a/linux/drivers/media/video/gspca/conex.c
+++ b/linux/drivers/media/video/gspca/conex.c
@@ -23,7 +23,6 @@
#include "gspca.h"
#define CONEX_CAM 1 /* special JPEG header */
-#define QUANT_VAL 0 /* quantization table */
#include "jpeg.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
@@ -37,6 +36,12 @@ struct sd {
unsigned char brightness;
unsigned char contrast;
unsigned char colors;
+ u8 quality;
+#define QUALITY_MIN 30
+#define QUALITY_MAX 60
+#define QUALITY_DEF 40
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -820,6 +825,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
+ sd->quality = QUALITY_DEF;
return 0;
}
@@ -836,6 +842,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
static int sd_start(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x22); /* JPEG 411 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
cx11646_initsize(gspca_dev);
cx11646_fw(gspca_dev);
cx_sensor(gspca_dev);
@@ -846,8 +860,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* called on streamoff with alt 0 and on disconnect */
static void sd_stop0(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
int retry = 50;
+ kfree(sd->jpeg_hdr);
+
if (!gspca_dev->present)
return;
reg_w_val(gspca_dev, 0x0000, 0x00);
@@ -873,6 +890,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
if (data[0] == 0xff && data[1] == 0xd8) {
/* start of frame */
@@ -880,7 +899,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data, 0);
/* put the JPEG header in the new frame */
- jpeg_put_header(gspca_dev, frame, 0x22);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
data += 2;
len -= 2;
}
@@ -983,6 +1003,34 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -993,6 +1041,8 @@ static struct sd_desc sd_desc = {
.start = sd_start,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
diff --git a/linux/drivers/media/video/gspca/finepix.c b/linux/drivers/media/video/gspca/finepix.c
index dc65c363a..480ec5c87 100644
--- a/linux/drivers/media/video/gspca/finepix.c
+++ b/linux/drivers/media/video/gspca/finepix.c
@@ -27,7 +27,7 @@ MODULE_DESCRIPTION("Fujifilm FinePix USB V4L2 driver");
MODULE_LICENSE("GPL");
/* Default timeout, in ms */
-#define FPIX_TIMEOUT (HZ / 10)
+#define FPIX_TIMEOUT 250
/* Maximum transfer size to use. The windows driver reads by chunks of
* 0x2000 bytes, so do the same. Note: reading more seems to work
@@ -38,38 +38,15 @@ MODULE_LICENSE("GPL");
struct usb_fpix {
struct gspca_dev gspca_dev; /* !! must be the first item */
- /*
- * USB stuff
- */
- struct usb_ctrlrequest ctrlreq;
- struct urb *control_urb;
- struct timer_list bulk_timer;
-
- enum {
- FPIX_NOP, /* inactive, else streaming */
- FPIX_RESET, /* must reset */
- FPIX_REQ_FRAME, /* requesting a frame */
- FPIX_READ_FRAME, /* reading frame */
- } state;
-
- /*
- * Driver stuff
- */
- struct delayed_work wqe;
- struct completion can_close;
- int streaming;
+ struct work_struct work_struct;
+ struct workqueue_struct *work_thread;
};
/* Delay after which claim the next frame. If the delay is too small,
* the camera will return old frames. On the 4800Z, 20ms is bad, 25ms
- * will fail every 4 or 5 frames, but 30ms is perfect. */
-#define NEXT_FRAME_DELAY (((HZ * 30) + 999) / 1000)
-
-#define dev_new_state(new_state) { \
- PDEBUG(D_STREAM, "new state from %d to %d at %s:%d", \
- dev->state, new_state, __func__, __LINE__); \
- dev->state = new_state; \
-}
+ * will fail every 4 or 5 frames, but 30ms is perfect. On the A210,
+ * 30ms is bad while 35ms is perfect. */
+#define NEXT_FRAME_DELAY 35
/* These cameras only support 320x200. */
static const struct v4l2_pix_format fpix_mode[1] = {
@@ -80,314 +57,184 @@ static const struct v4l2_pix_format fpix_mode[1] = {
.priv = 0}
};
-/* Reads part of a frame */
-static void read_frame_part(struct usb_fpix *dev)
+/* send a command to the webcam */
+static int command(struct gspca_dev *gspca_dev,
+ int order) /* 0: reset, 1: frame request */
{
- int ret;
+ static u8 order_values[2][12] = {
+ {0xc6, 0, 0, 0, 0, 0, 0, 0, 0x20, 0, 0, 0}, /* reset */
+ {0xd3, 0, 0, 0, 0, 0, 0, 0x01, 0, 0, 0, 0}, /* fr req */
+ };
- PDEBUG(D_STREAM, "read_frame_part");
-
- /* Reads part of a frame */
- ret = usb_submit_urb(dev->gspca_dev.urb[0], GFP_ATOMIC);
- if (ret) {
- dev_new_state(FPIX_RESET);
- schedule_delayed_work(&dev->wqe, 1);
- PDEBUG(D_STREAM, "usb_submit_urb failed with %d",
- ret);
- } else {
- /* Sometimes we never get a callback, so use a timer.
- * Is this masking a bug somewhere else? */
- dev->bulk_timer.expires = jiffies + msecs_to_jiffies(150);
- add_timer(&dev->bulk_timer);
- }
+ memcpy(gspca_dev->usb_buf, order_values[order], 12);
+ return usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ USB_REQ_GET_STATUS,
+ USB_DIR_OUT | USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
+ 12, FPIX_TIMEOUT);
}
-/* Callback for URBs. */
-static void urb_callback(struct urb *urb)
+/* workqueue */
+static void dostream(struct work_struct *work)
{
- struct gspca_dev *gspca_dev = urb->context;
- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-
- PDEBUG(D_PACK,
- "enter urb_callback - status=%d, length=%d",
- urb->status, urb->actual_length);
-
- if (dev->state == FPIX_READ_FRAME)
- del_timer(&dev->bulk_timer);
-
- if (urb->status != 0) {
- /* We kill a stuck urb every 50 frames on average, so don't
- * display a log message for that. */
- if (urb->status != -ECONNRESET)
- PDEBUG(D_STREAM, "bad URB status %d", urb->status);
- dev_new_state(FPIX_RESET);
- schedule_delayed_work(&dev->wqe, 1);
- }
-
- switch (dev->state) {
- case FPIX_REQ_FRAME:
- dev_new_state(FPIX_READ_FRAME);
- read_frame_part(dev);
- break;
-
- case FPIX_READ_FRAME: {
- unsigned char *data = urb->transfer_buffer;
- struct gspca_frame *frame;
-
- frame = gspca_get_i_frame(&dev->gspca_dev);
- if (frame == NULL)
- gspca_dev->last_packet_type = DISCARD_PACKET;
- if (urb->actual_length < FPIX_MAX_TRANSFER ||
- (data[urb->actual_length-2] == 0xff &&
- data[urb->actual_length-1] == 0xd9)) {
-
- /* If the result is less than what was asked
- * for, then it's the end of the
- * frame. Sometime the jpeg is not complete,
- * but there's nothing we can do. We also end
- * here if the the jpeg ends right at the end
- * of the frame. */
- if (frame)
- gspca_frame_add(gspca_dev, LAST_PACKET,
- frame,
- data, urb->actual_length);
- dev_new_state(FPIX_REQ_FRAME);
- schedule_delayed_work(&dev->wqe, NEXT_FRAME_DELAY);
- } else {
+ struct usb_fpix *dev = container_of(work, struct usb_fpix, work_struct);
+ struct gspca_dev *gspca_dev = &dev->gspca_dev;
+ struct urb *urb = gspca_dev->urb[0];
+ u8 *data = urb->transfer_buffer;
+ struct gspca_frame *frame;
+ int ret = 0;
+ int len;
+
+ /* synchronize with the main driver */
+ mutex_lock(&gspca_dev->usb_lock);
+ mutex_unlock(&gspca_dev->usb_lock);
+ PDEBUG(D_STREAM, "dostream started");
+
+ /* loop reading a frame */
+again:
+ while (gspca_dev->present && gspca_dev->streaming) {
+
+ /* request a frame */
+ mutex_lock(&gspca_dev->usb_lock);
+ ret = command(gspca_dev, 1);
+ mutex_unlock(&gspca_dev->usb_lock);
+ if (ret < 0)
+ break;
+ if (!gspca_dev->present || !gspca_dev->streaming)
+ break;
+
+ /* the frame comes in parts */
+ for (;;) {
+ ret = usb_bulk_msg(gspca_dev->dev,
+ urb->pipe,
+ data,
+ FPIX_MAX_TRANSFER,
+ &len, FPIX_TIMEOUT);
+ if (ret < 0) {
+ /* Most of the time we get a timeout
+ * error. Just restart. */
+ goto again;
+ }
+ if (!gspca_dev->present || !gspca_dev->streaming)
+ goto out;
+ frame = gspca_get_i_frame(&dev->gspca_dev);
+ if (frame == NULL)
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+
+ if (len < FPIX_MAX_TRANSFER ||
+ (data[len - 2] == 0xff &&
+ data[len - 1] == 0xd9)) {
+
+ /* If the result is less than what was asked
+ * for, then it's the end of the
+ * frame. Sometimes the jpeg is not complete,
+ * but there's nothing we can do. We also end
+ * here if the the jpeg ends right at the end
+ * of the frame. */
+ if (frame)
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
+ frame,
+ data, len);
+ break;
+ }
/* got a partial image */
if (frame)
gspca_frame_add(gspca_dev,
gspca_dev->last_packet_type
- == LAST_PACKET
+ == LAST_PACKET
? FIRST_PACKET : INTER_PACKET,
- frame,
- data, urb->actual_length);
- read_frame_part(dev);
+ frame, data, len);
}
- break;
- }
-
- case FPIX_NOP:
- case FPIX_RESET:
- PDEBUG(D_STREAM, "invalid state %d", dev->state);
- break;
- }
-}
-
-/* Request a new frame */
-static void request_frame(struct usb_fpix *dev)
-{
- int ret;
- struct gspca_dev *gspca_dev = &dev->gspca_dev;
- /* Setup command packet */
- memset(gspca_dev->usb_buf, 0, 12);
- gspca_dev->usb_buf[0] = 0xd3;
- gspca_dev->usb_buf[7] = 0x01;
-
- /* Request a frame */
- dev->ctrlreq.bRequestType =
- USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE;
- dev->ctrlreq.bRequest = USB_REQ_GET_STATUS;
- dev->ctrlreq.wValue = 0;
- dev->ctrlreq.wIndex = 0;
- dev->ctrlreq.wLength = cpu_to_le16(12);
-
- usb_fill_control_urb(dev->control_urb,
- gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- (unsigned char *) &dev->ctrlreq,
- gspca_dev->usb_buf,
- 12, urb_callback, gspca_dev);
-
- ret = usb_submit_urb(dev->control_urb, GFP_ATOMIC);
- if (ret) {
- dev_new_state(FPIX_RESET);
- schedule_delayed_work(&dev->wqe, 1);
- PDEBUG(D_STREAM, "usb_submit_urb failed with %d", ret);
+ /* We must wait before trying reading the next
+ * frame. If we don't, or if the delay is too short,
+ * the camera will disconnect. */
+ msleep(NEXT_FRAME_DELAY);
}
-}
-
-/*--------------------------------------------------------------------------*/
-/* State machine. */
-static void fpix_sm(struct work_struct *work)
-{
- struct usb_fpix *dev = container_of(work, struct usb_fpix, wqe.work);
-
- PDEBUG(D_STREAM, "fpix_sm state %d", dev->state);
-
- /* verify that the device wasn't unplugged */
- if (!dev->gspca_dev.present) {
- PDEBUG(D_STREAM, "device is gone");
- dev_new_state(FPIX_NOP);
- complete(&dev->can_close);
- return;
- }
-
- if (!dev->streaming) {
- PDEBUG(D_STREAM, "stopping state machine");
- dev_new_state(FPIX_NOP);
- complete(&dev->can_close);
- return;
- }
-
- switch (dev->state) {
- case FPIX_RESET:
- dev_new_state(FPIX_REQ_FRAME);
- schedule_delayed_work(&dev->wqe, HZ / 10);
- break;
-
- case FPIX_REQ_FRAME:
- /* get an image */
- request_frame(dev);
- break;
-
- case FPIX_NOP:
- case FPIX_READ_FRAME:
- PDEBUG(D_STREAM, "invalid state %d", dev->state);
- break;
- }
+out:
+ PDEBUG(D_STREAM, "dostream stopped");
}
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
+ struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
struct cam *cam = &gspca_dev->cam;
cam->cam_mode = fpix_mode;
cam->nmodes = 1;
+ cam->bulk = 1;
cam->bulk_size = FPIX_MAX_TRANSFER;
-/* gspca_dev->nbalt = 1; * use bulk transfer */
- return 0;
-}
-
-/* Stop streaming and free the ressources allocated by sd_start. */
-static void sd_stopN(struct gspca_dev *gspca_dev)
-{
- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
+ INIT_WORK(&dev->work_struct, dostream);
- dev->streaming = 0;
-
- /* Stop the state machine */
- if (dev->state != FPIX_NOP)
- wait_for_completion(&dev->can_close);
-}
-
-/* called on streamoff with alt 0 and disconnect */
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-
- usb_free_urb(dev->control_urb);
- dev->control_urb = NULL;
-}
-
-/* Kill an URB that hasn't completed. */
-static void timeout_kill(unsigned long data)
-{
- struct urb *urb = (struct urb *) data;
-
- usb_unlink_urb(urb);
+ return 0;
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-
- INIT_DELAYED_WORK(&dev->wqe, fpix_sm);
-
- init_timer(&dev->bulk_timer);
- dev->bulk_timer.function = timeout_kill;
-
return 0;
}
+/* start the camera */
static int sd_start(struct gspca_dev *gspca_dev)
{
struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
- int ret;
- int size_ret;
+ int ret, len;
/* Init the device */
- memset(gspca_dev->usb_buf, 0, 12);
- gspca_dev->usb_buf[0] = 0xc6;
- gspca_dev->usb_buf[8] = 0x20;
-
- ret = usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- USB_REQ_GET_STATUS,
- USB_DIR_OUT | USB_TYPE_CLASS |
- USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
- 12, FPIX_TIMEOUT);
-
- if (ret != 12) {
- PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
- ret = -EIO;
- goto error;
+ ret = command(gspca_dev, 0);
+ if (ret < 0) {
+ PDEBUG(D_STREAM, "init failed %d", ret);
+ return ret;
}
/* Read the result of the command. Ignore the result, for it
* varies with the device. */
ret = usb_bulk_msg(gspca_dev->dev,
gspca_dev->urb[0]->pipe,
- gspca_dev->usb_buf, FPIX_MAX_TRANSFER, &size_ret,
+ gspca_dev->urb[0]->transfer_buffer,
+ FPIX_MAX_TRANSFER, &len,
FPIX_TIMEOUT);
- if (ret != 0) {
- PDEBUG(D_STREAM, "usb_bulk_msg failed (%d)", ret);
- ret = -EIO;
- goto error;
+ if (ret < 0) {
+ PDEBUG(D_STREAM, "usb_bulk_msg failed %d", ret);
+ return ret;
}
/* Request a frame, but don't read it */
- memset(gspca_dev->usb_buf, 0, 12);
- gspca_dev->usb_buf[0] = 0xd3;
- gspca_dev->usb_buf[7] = 0x01;
-
- ret = usb_control_msg(gspca_dev->dev,
- usb_sndctrlpipe(gspca_dev->dev, 0),
- USB_REQ_GET_STATUS,
- USB_DIR_OUT | USB_TYPE_CLASS |
- USB_RECIP_INTERFACE, 0, 0, gspca_dev->usb_buf,
- 12, FPIX_TIMEOUT);
- if (ret != 12) {
- PDEBUG(D_STREAM, "usb_control_msg failed (%d)", ret);
- ret = -EIO;
- goto error;
+ ret = command(gspca_dev, 1);
+ if (ret < 0) {
+ PDEBUG(D_STREAM, "frame request failed %d", ret);
+ return ret;
}
/* Again, reset bulk in endpoint */
usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
- /* Allocate a control URB */
- dev->control_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!dev->control_urb) {
- PDEBUG(D_STREAM, "No free urbs available");
- ret = -EIO;
- goto error;
- }
-
- /* Various initializations. */
- init_completion(&dev->can_close);
- dev->bulk_timer.data = (unsigned long)dev->gspca_dev.urb[0];
- dev->gspca_dev.urb[0]->complete = urb_callback;
- dev->streaming = 1;
-
- /* Schedule a frame request. */
- dev_new_state(FPIX_REQ_FRAME);
- schedule_delayed_work(&dev->wqe, 1);
+ /* Start the workqueue function to do the streaming */
+ dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
+ queue_work(dev->work_thread, &dev->work_struct);
return 0;
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct usb_fpix *dev = (struct usb_fpix *) gspca_dev;
-error:
- /* Free the ressources */
- sd_stopN(gspca_dev);
- sd_stop0(gspca_dev);
- return ret;
+ /* wait for the work queue to terminate */
+ mutex_unlock(&gspca_dev->usb_lock);
+ destroy_workqueue(dev->work_thread);
+ mutex_lock(&gspca_dev->usb_lock);
+ dev->work_thread = NULL;
}
/* Table of supported USB devices */
@@ -422,12 +269,11 @@ MODULE_DEVICE_TABLE(usb, device_table);
/* sub-driver description */
static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
+ .name = MODULE_NAME,
.config = sd_config,
- .init = sd_init,
- .start = sd_start,
- .stopN = sd_stopN,
- .stop0 = sd_stop0,
+ .init = sd_init,
+ .start = sd_start,
+ .stop0 = sd_stop0,
};
/* -- device connect -- */
@@ -441,13 +287,13 @@ static int sd_probe(struct usb_interface *intf,
}
static struct usb_driver sd_driver = {
- .name = MODULE_NAME,
- .id_table = device_table,
- .probe = sd_probe,
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
.disconnect = gspca_disconnect,
#ifdef CONFIG_PM
.suspend = gspca_suspend,
- .resume = gspca_resume,
+ .resume = gspca_resume,
#endif
};
@@ -455,12 +301,14 @@ static struct usb_driver sd_driver = {
static int __init sd_mod_init(void)
{
int ret;
+
ret = usb_register(&sd_driver);
if (ret < 0)
return ret;
PDEBUG(D_PROBE, "registered");
return 0;
}
+
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
diff --git a/linux/drivers/media/video/gspca/gspca.c b/linux/drivers/media/video/gspca/gspca.c
index d629ce1dc..3bf8b4866 100644
--- a/linux/drivers/media/video/gspca/gspca.c
+++ b/linux/drivers/media/video/gspca/gspca.c
@@ -1,7 +1,7 @@
/*
* Main USB camera driver
*
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2008-2009 Jean-Francois Moine (http://moinejf.free.fr)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -51,7 +51,7 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 5, 0)
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 6, 0)
#ifdef GSPCA_DEBUG
int gspca_debug = D_ERR | D_PROBE;
@@ -453,7 +453,7 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
* look for an input transfer endpoint in an alternate setting
*/
static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
- __u8 xfer)
+ int xfer)
{
struct usb_host_endpoint *ep;
int i, attr;
@@ -461,7 +461,8 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt,
for (i = 0; i < alt->desc.bNumEndpoints; i++) {
ep = &alt->endpoint[i];
attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
- if (attr == xfer)
+ if (attr == xfer
+ && ep->desc.wMaxPacketSize != 0)
return ep;
}
return NULL;
@@ -479,35 +480,28 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
{
struct usb_interface *intf;
struct usb_host_endpoint *ep;
- int i, ret;
+ int xfer, i, ret;
intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
ep = NULL;
+ xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
+ : USB_ENDPOINT_XFER_ISOC;
i = gspca_dev->alt; /* previous alt setting */
-
- /* try isoc */
- while (--i > 0) { /* alt 0 is unusable */
- ep = alt_xfer(&intf->altsetting[i],
- USB_ENDPOINT_XFER_ISOC);
+ while (--i >= 0) {
+ ep = alt_xfer(&intf->altsetting[i], xfer);
if (ep)
break;
}
-
- /* if no isoc, try bulk */
if (ep == NULL) {
- ep = alt_xfer(&intf->altsetting[0],
- USB_ENDPOINT_XFER_BULK);
- if (ep == NULL) {
- err("no transfer endpoint found");
- return NULL;
- }
+ err("no transfer endpoint found");
+ return NULL;
}
PDEBUG(D_STREAM, "use alt %d ep 0x%02x",
i, ep->desc.bEndpointAddress);
- if (i > 0) {
+ if (gspca_dev->nbalt > 1) {
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
if (ret < 0) {
- err("set interface err %d", ret);
+ err("set alt %d err %d", i, ret);
return NULL;
}
}
@@ -527,13 +521,13 @@ static int create_urbs(struct gspca_dev *gspca_dev,
/* calculate the packet size and the number of packets */
psize = le16_to_cpu(ep->desc.wMaxPacketSize);
- if (gspca_dev->alt != 0) { /* isoc */
+ if (!gspca_dev->cam.bulk) { /* isoc */
/* See paragraph 5.9 / table 5-11 of the usb 2.0 spec. */
psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
- npkt = ISO_MAX_SIZE / psize;
- if (npkt > ISO_MAX_PKT)
- npkt = ISO_MAX_PKT;
+ npkt = gspca_dev->cam.npkt;
+ if (npkt == 0)
+ npkt = 32; /* default value */
bsize = psize * npkt;
PDEBUG(D_STREAM,
"isoc %d pkts size %d = bsize:%d",
@@ -627,7 +621,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
goto out;
/* clear the bulk endpoint */
- if (gspca_dev->alt == 0) /* if bulk transfer */
+ if (gspca_dev->cam.bulk)
usb_clear_halt(gspca_dev->dev,
gspca_dev->urb[0]->pipe);
@@ -640,7 +634,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
gspca_dev->streaming = 1;
/* some bulk transfers are started by the subdriver */
- if (gspca_dev->alt == 0 && gspca_dev->cam.bulk_nurbs == 0)
+ if (gspca_dev->cam.bulk && gspca_dev->cam.bulk_nurbs == 0)
break;
/* submit the URBs */
@@ -671,6 +665,8 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
{
int ret;
+ if (gspca_dev->alt == 0)
+ return 0;
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
if (ret < 0)
PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret);
@@ -775,7 +771,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
fmtdesc->pixelformat = fmt_tb[index];
if (gspca_is_compressed(fmt_tb[index]))
fmtdesc->flags = V4L2_FMT_FLAG_COMPRESSED;
- fmtdesc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmtdesc->description[0] = fmtdesc->pixelformat & 0xff;
fmtdesc->description[1] = (fmtdesc->pixelformat >> 8) & 0xff;
fmtdesc->description[2] = (fmtdesc->pixelformat >> 16) & 0xff;
@@ -880,6 +875,32 @@ out:
return ret;
}
+static int vidioc_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct gspca_dev *gspca_dev = priv;
+ int i;
+ __u32 index = 0;
+
+ for (i = 0; i < gspca_dev->cam.nmodes; i++) {
+ if (fsize->pixel_format !=
+ gspca_dev->cam.cam_mode[i].pixelformat)
+ continue;
+
+ if (fsize->index == index) {
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width =
+ gspca_dev->cam.cam_mode[i].width;
+ fsize->discrete.height =
+ gspca_dev->cam.cam_mode[i].height;
+ return 0;
+ }
+ index++;
+ }
+
+ return -EINVAL;
+}
+
static void gspca_release(struct video_device *vfd)
{
struct gspca_dev *gspca_dev = container_of(vfd, struct gspca_dev, vdev);
@@ -972,8 +993,6 @@ static int vidioc_querycap(struct file *file, void *priv,
struct gspca_dev *gspca_dev = priv;
int ret;
- memset(cap, 0, sizeof *cap);
-
/* protect the access to the usb device */
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
@@ -1145,6 +1164,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
if (input->index != 0)
return -EINVAL;
input->type = V4L2_INPUT_TYPE_CAMERA;
+ input->status = gspca_dev->cam.input_flags;
strncpy(input->name, gspca_dev->sd_desc->name,
sizeof input->name);
return 0;
@@ -1351,7 +1371,6 @@ static int vidioc_g_parm(struct file *filp, void *priv,
{
struct gspca_dev *gspca_dev = priv;
- parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
parm->parm.capture.readbuffers = gspca_dev->nbufread;
if (gspca_dev->sd_desc->get_streamparm) {
@@ -1877,6 +1896,7 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_g_parm = vidioc_g_parm,
.vidioc_s_parm = vidioc_s_parm,
.vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_framesizes = vidioc_enum_framesizes,
#ifdef CONFIG_VIDEO_V4L1_COMPAT
.vidiocgmbuf = vidiocgmbuf,
#endif
@@ -1956,7 +1976,7 @@ int gspca_dev_probe(struct usb_interface *intf,
/* init video stuff */
memcpy(&gspca_dev->vdev, &gspca_template, sizeof gspca_template);
- gspca_dev->vdev.parent = &dev->dev;
+ gspca_dev->vdev.parent = &intf->dev;
gspca_dev->module = module;
gspca_dev->present = 1;
ret = video_register_device(&gspca_dev->vdev,
diff --git a/linux/drivers/media/video/gspca/gspca.h b/linux/drivers/media/video/gspca/gspca.h
index 6f172e9e5..bd1faff88 100644
--- a/linux/drivers/media/video/gspca/gspca.h
+++ b/linux/drivers/media/video/gspca/gspca.h
@@ -44,8 +44,6 @@ extern int gspca_debug;
#define GSPCA_MAX_FRAMES 16 /* maximum number of video frame buffers */
/* image transfers */
#define MAX_NURBS 4 /* max number of URBs */
-#define ISO_MAX_PKT 32 /* max number of packets in an ISOC transfer */
-#define ISO_MAX_SIZE 0x8000 /* max size of one URB buffer (32 Kb) */
/* device information - set at probe time */
struct cam {
@@ -56,6 +54,10 @@ struct cam {
* - cannot be > MAX_NURBS
* - when 0 and bulk_size != 0 means
* 1 URB and submit done by subdriver */
+ u8 bulk; /* image transfer by 0:isoc / 1:bulk */
+ u8 npkt; /* number of packets in an ISOC message
+ * 0 is the default value: 32 packets */
+ u32 input_flags; /* value for ENUM_INPUT status flags */
};
struct gspca_dev;
diff --git a/linux/drivers/media/video/gspca/jpeg.h b/linux/drivers/media/video/gspca/jpeg.h
index 7d2df9720..de63c3680 100644
--- a/linux/drivers/media/video/gspca/jpeg.h
+++ b/linux/drivers/media/video/gspca/jpeg.h
@@ -27,42 +27,16 @@
/*
* generation options
* CONEX_CAM Conexant if present
- * QUANT_VAL quantization table (0..8)
*/
-/*
- * JPEG header:
- * - start of jpeg frame
- * - quantization table
- * - huffman table
- * - start of SOF0
- */
+/* JPEG header */
static const u8 jpeg_head[] = {
0xff, 0xd8, /* jpeg */
+
+/* quantization table quality 50% */
0xff, 0xdb, 0x00, 0x84, /* DQT */
-#if QUANT_VAL == 0
-/* index 0 - Q40*/
-0, /* quantization table part 1 */
- 0x14, 0x0e, 0x0f, 0x12, 0x0f, 0x0d, 0x14, 0x12,
- 0x10, 0x12, 0x17, 0x15, 0x14, 0x18, 0x1e, 0x32,
- 0x21, 0x1e, 0x1c, 0x1c, 0x1e, 0x3d, 0x2c, 0x2e,
- 0x24, 0x32, 0x49, 0x40, 0x4c, 0x4b, 0x47, 0x40,
- 0x46, 0x45, 0x50, 0x5a, 0x73, 0x62, 0x50, 0x55,
- 0x6d, 0x56, 0x45, 0x46, 0x64, 0x88, 0x65, 0x6d,
- 0x77, 0x7b, 0x81, 0x82, 0x81, 0x4e, 0x60, 0x8d,
- 0x97, 0x8c, 0x7d, 0x96, 0x73, 0x7e, 0x81, 0x7c,
-1, /* quantization table part 2 */
- 0x15, 0x17, 0x17, 0x1e, 0x1a, 0x1e, 0x3b, 0x21,
- 0x21, 0x3b, 0x7c, 0x53, 0x46, 0x53, 0x7c, 0x0c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
- 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c,
-#elif QUANT_VAL == 1
-/* index 1 - Q50 */
0,
+#define JPEG_QT0_OFFSET 7
0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e,
0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28,
0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25,
@@ -72,6 +46,7 @@ static const u8 jpeg_head[] = {
0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71,
0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63,
1,
+#define JPEG_QT1_OFFSET 72
0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a,
0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
@@ -80,149 +55,6 @@ static const u8 jpeg_head[] = {
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
-#elif QUANT_VAL == 2
-/* index 2 Q60 */
-0,
- 0x0d, 0x09, 0x0a, 0x0b, 0x0a, 0x08, 0x0d, 0x0b,
- 0x0a, 0x0b, 0x0e, 0x0e, 0x0d, 0x0f, 0x13, 0x20,
- 0x15, 0x13, 0x12, 0x12, 0x13, 0x27, 0x1c, 0x1e,
- 0x17, 0x20, 0x2e, 0x29, 0x31, 0x30, 0x2e, 0x29,
- 0x2d, 0x2c, 0x33, 0x3a, 0x4a, 0x3e, 0x33, 0x36,
- 0x46, 0x37, 0x2c, 0x2d, 0x40, 0x57, 0x41, 0x46,
- 0x4c, 0x4e, 0x52, 0x53, 0x52, 0x32, 0x3e, 0x5a,
- 0x61, 0x5a, 0x50, 0x60, 0x4a, 0x51, 0x52, 0x4f,
-1,
- 0x0e, 0x0e, 0x0e, 0x13, 0x11, 0x13, 0x26, 0x15,
- 0x15, 0x26, 0x4f, 0x35, 0x2d, 0x35, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
- 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f,
-#elif QUANT_VAL == 3
-/* index 3 - Q70 */
-0,
- 0x0a, 0x07, 0x07, 0x08, 0x07, 0x06, 0x0a, 0x08,
- 0x08, 0x08, 0x0b, 0x0a, 0x0a, 0x0b, 0x0e, 0x18,
- 0x10, 0x0e, 0x0d, 0x0d, 0x0e, 0x1d, 0x15, 0x16,
- 0x11, 0x18, 0x23, 0x1f, 0x25, 0x24, 0x22, 0x1f,
- 0x22, 0x21, 0x26, 0x2b, 0x37, 0x2f, 0x26, 0x29,
- 0x34, 0x29, 0x21, 0x22, 0x30, 0x41, 0x31, 0x34,
- 0x39, 0x3b, 0x3e, 0x3e, 0x3e, 0x25, 0x2e, 0x44,
- 0x49, 0x43, 0x3c, 0x48, 0x37, 0x3d, 0x3e, 0x3b,
-1,
- 0x0a, 0x0b, 0x0b, 0x0e, 0x0d, 0x0e, 0x1c, 0x10,
- 0x10, 0x1c, 0x3b, 0x28, 0x22, 0x28, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
- 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b, 0x3b,
-#elif QUANT_VAL == 4
-/* index 4 - Q80 */
-0,
- 0x06, 0x04, 0x05, 0x06, 0x05, 0x04, 0x06, 0x06,
- 0x05, 0x06, 0x07, 0x07, 0x06, 0x08, 0x0a, 0x10,
- 0x0a, 0x0a, 0x09, 0x09, 0x0a, 0x14, 0x0e, 0x0f,
- 0x0c, 0x10, 0x17, 0x14, 0x18, 0x18, 0x17, 0x14,
- 0x16, 0x16, 0x1a, 0x1d, 0x25, 0x1f, 0x1a, 0x1b,
- 0x23, 0x1c, 0x16, 0x16, 0x20, 0x2c, 0x20, 0x23,
- 0x26, 0x27, 0x29, 0x2a, 0x29, 0x19, 0x1f, 0x2d,
- 0x30, 0x2d, 0x28, 0x30, 0x25, 0x28, 0x29, 0x28,
-1,
- 0x07, 0x07, 0x07, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
- 0x0a, 0x13, 0x28, 0x1a, 0x16, 0x1a, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
- 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28,
-#elif QUANT_VAL == 5
-/* index 5 - Q85 */
-0,
- 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04,
- 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c,
- 0x08, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b,
- 0x09, 0x0c, 0x11, 0x0f, 0x12, 0x12, 0x11, 0x0f,
- 0x11, 0x11, 0x13, 0x16, 0x1c, 0x17, 0x13, 0x14,
- 0x1a, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1a,
- 0x1d, 0x1d, 0x1f, 0x1f, 0x1f, 0x13, 0x17, 0x22,
- 0x24, 0x22, 0x1e, 0x24, 0x1c, 0x1e, 0x1f, 0x1e,
-1,
- 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0e, 0x08,
- 0x08, 0x0e, 0x1e, 0x14, 0x11, 0x14, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
- 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
-#elif QUANT_VAL == 6
-/* index 6 - 86 */
-0,
- 0x04, 0x03, 0x03, 0x04, 0x03, 0x03, 0x04, 0x04,
- 0x04, 0x04, 0x05, 0x05, 0x04, 0x05, 0x07, 0x0B,
- 0x07, 0x07, 0x06, 0x06, 0x07, 0x0e, 0x0a, 0x0a,
- 0x08, 0x0B, 0x10, 0x0e, 0x11, 0x11, 0x10, 0x0e,
- 0x10, 0x0f, 0x12, 0x14, 0x1a, 0x16, 0x12, 0x13,
- 0x18, 0x13, 0x0f, 0x10, 0x16, 0x1f, 0x17, 0x18,
- 0x1b, 0x1b, 0x1d, 0x1d, 0x1d, 0x11, 0x16, 0x20,
- 0x22, 0x1f, 0x1c, 0x22, 0x1a, 0x1c, 0x1d, 0x1c,
-1,
- 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x0D, 0x07,
- 0x07, 0x0D, 0x1c, 0x12, 0x10, 0x12, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
- 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c,
-#elif QUANT_VAL == 7
-/* index 7 - 88 */
-0,
- 0x04, 0x03, 0x03, 0x03, 0x03, 0x02, 0x04, 0x03,
- 0x03, 0x03, 0x04, 0x04, 0x04, 0x05, 0x06, 0x0a,
- 0x06, 0x06, 0x05, 0x05, 0x06, 0x0C, 0x08, 0x09,
- 0x07, 0x0a, 0x0e, 0x0c, 0x0f, 0x0e, 0x0e, 0x0c,
- 0x0d, 0x0d, 0x0f, 0x11, 0x16, 0x13, 0x0f, 0x10,
- 0x15, 0x11, 0x0d, 0x0d, 0x13, 0x1a, 0x13, 0x15,
- 0x17, 0x18, 0x19, 0x19, 0x19, 0x0f, 0x12, 0x1b,
- 0x1d, 0x1b, 0x18, 0x1d, 0x16, 0x18, 0x19, 0x18,
-1,
- 0x04, 0x04, 0x04, 0x06, 0x05, 0x06, 0x0B, 0x06,
- 0x06, 0x0B, 0x18, 0x10, 0x0d, 0x10, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
- 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
-#elif QUANT_VAL == 8
-/* index 8 - ?? */
-0,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
- 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, 0x05,
- 0x03, 0x03, 0x03, 0x03, 0x03, 0x06, 0x04, 0x05,
- 0x04, 0x05, 0x07, 0x06, 0x08, 0x08, 0x07, 0x06,
- 0x07, 0x07, 0x08, 0x09, 0x0c, 0x0a, 0x08, 0x09,
- 0x0B, 0x09, 0x07, 0x07, 0x0a, 0x0e, 0x0a, 0x0b,
- 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x08, 0x0a, 0x0e,
- 0x0f, 0x0e, 0x0d, 0x0f, 0x0c, 0x0d, 0x0d, 0x0c,
-1,
- 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x06, 0x03,
- 0x03, 0x06, 0x0c, 0x08, 0x07, 0x08, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
- 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
-#else
-#error "Invalid quantization table"
-#endif
/* huffman table */
0xff, 0xc4, 0x01, 0xa2,
@@ -280,55 +112,57 @@ static const u8 jpeg_head[] = {
0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa,
#ifdef CONEX_CAM
/* the Conexant frames start with SOF0 */
+#define JPEG_HDR_SZ 556
#else
0xff, 0xc0, 0x00, 0x11, /* SOF0 (start of frame 0 */
0x08, /* data precision */
-#endif
-};
-
-#ifndef CONEX_CAM
-/* variable part:
- * 0x01, 0xe0, height
- * 0x02, 0x80, width
- * 0x03, component number
- * 0x01,
- * 0x21, samples Y
- */
-
-/* end of header */
-static u8 eoh[] = {
+#define JPEG_HEIGHT_OFFSET 561
+ 0x01, 0xe0, /* height */
+ 0x02, 0x80, /* width */
+ 0x03, /* component number */
+ 0x01,
+ 0x21, /* samples Y */
0x00, /* quant Y */
0x02, 0x11, 0x01, /* samples CbCr - quant CbCr */
0x03, 0x11, 0x01,
0xff, 0xda, 0x00, 0x0c, /* SOS (start of scan) */
0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00
-};
+#define JPEG_HDR_SZ 589
#endif
+};
-/* -- output the JPEG header -- */
-static void jpeg_put_header(struct gspca_dev *gspca_dev,
- struct gspca_frame *frame,
- int samplesY)
+/* define the JPEG header */
+static void jpeg_define(u8 *jpeg_hdr,
+ int height,
+ int width,
+ int samplesY)
{
+ memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head);
#ifndef CONEX_CAM
- u8 tmpbuf[8];
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height & 0xff;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width & 0xff;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 6] = samplesY;
#endif
+}
- gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
- jpeg_head, sizeof jpeg_head);
-#ifndef CONEX_CAM
- tmpbuf[0] = gspca_dev->height >> 8;
- tmpbuf[1] = gspca_dev->height & 0xff;
- tmpbuf[2] = gspca_dev->width >> 8;
- tmpbuf[3] = gspca_dev->width & 0xff;
- tmpbuf[4] = 0x03; /* component number */
- tmpbuf[5] = 0x01; /* first component */
- tmpbuf[6] = samplesY;
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- tmpbuf, 7);
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- eoh, sizeof eoh);
-#endif
+/* set the JPEG quality */
+static void jpeg_set_qual(u8 *jpeg_hdr,
+ int quality)
+{
+ int i, sc;
+
+ if (quality < 50)
+ sc = 5000 / quality;
+ else
+ sc = 200 - quality * 2;
+ for (i = 0; i < 64; i++) {
+ jpeg_hdr[JPEG_QT0_OFFSET + i] =
+ (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
+ jpeg_hdr[JPEG_QT1_OFFSET + i] =
+ (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
+ }
}
#endif
diff --git a/linux/drivers/media/video/gspca/m5602/Makefile b/linux/drivers/media/video/gspca/m5602/Makefile
index 226ab4fc9..bf7a19a1e 100644
--- a/linux/drivers/media/video/gspca/m5602/Makefile
+++ b/linux/drivers/media/video/gspca/m5602/Makefile
@@ -2,10 +2,10 @@ obj-$(CONFIG_USB_M5602) += gspca_m5602.o
gspca_m5602-objs := m5602_core.o \
m5602_ov9650.o \
+ m5602_ov7660.o \
m5602_mt9m111.o \
m5602_po1030.o \
m5602_s5k83a.o \
m5602_s5k4aa.o
EXTRA_CFLAGS += -Idrivers/media/video/gspca
-
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_bridge.h b/linux/drivers/media/video/gspca/m5602/m5602_bridge.h
index a3f3b7a0c..1127a405c 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_bridge.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_bridge.h
@@ -45,6 +45,15 @@
#define M5602_XB_SEN_CLK_DIV 0x15
#define M5602_XB_AUD_CLK_CTRL 0x16
#define M5602_XB_AUD_CLK_DIV 0x17
+#define M5602_OB_AC_LINK_STATE 0x22
+#define M5602_OB_PCM_SLOT_INDEX 0x24
+#define M5602_OB_GPIO_SLOT_INDEX 0x25
+#define M5602_OB_ACRX_STATUS_ADDRESS_H 0x28
+#define M5602_OB_ACRX_STATUS_DATA_L 0x29
+#define M5602_OB_ACRX_STATUS_DATA_H 0x2a
+#define M5602_OB_ACTX_COMMAND_ADDRESS 0x31
+#define M5602_OB_ACRX_COMMAND_DATA_L 0x32
+#define M5602_OB_ACTX_COMMAND_DATA_H 0X33
#define M5602_XB_DEVCTR1 0x41
#define M5602_XB_EPSETR0 0x42
#define M5602_XB_EPAFCTR 0x47
@@ -77,7 +86,18 @@
#define M5602_XB_GPIO_EN_L 0x75
#define M5602_XB_GPIO_DAT 0x76
#define M5602_XB_GPIO_DIR 0x77
-#define M5602_XB_MISC_CTL 0x70
+#define M5602_XB_SEN_CLK_CONTROL 0x80
+#define M5602_XB_SEN_CLK_DIVISION 0x81
+#define M5602_XB_CPR_CLK_CONTROL 0x82
+#define M5602_XB_CPR_CLK_DIVISION 0x83
+#define M5602_XB_MCU_CLK_CONTROL 0x84
+#define M5602_XB_MCU_CLK_DIVISION 0x85
+#define M5602_XB_DCT_CLK_CONTROL 0x86
+#define M5602_XB_DCT_CLK_DIVISION 0x87
+#define M5602_XB_EC_CLK_CONTROL 0x88
+#define M5602_XB_EC_CLK_DIVISION 0x89
+#define M5602_XB_LBUF_CLK_CONTROL 0x8a
+#define M5602_XB_LBUF_CLK_DIVISION 0x8b
#define I2C_BUSY 0x80
@@ -112,14 +132,14 @@ static const unsigned char sensor_urb_skeleton[] = {
struct sd {
struct gspca_dev gspca_dev;
- /* The name of the m5602 camera */
- char *name;
-
/* A pointer to the currently connected sensor */
- struct m5602_sensor *sensor;
+ const struct m5602_sensor *sensor;
struct sd_desc *desc;
+ /* Sensor private data */
+ void *sensor_priv;
+
/* The current frame's id, used to detect frame boundaries */
u8 frame_id;
@@ -128,10 +148,10 @@ struct sd {
};
int m5602_read_bridge(
- struct sd *sd, u8 address, u8 *i2c_data);
+ struct sd *sd, const u8 address, u8 *i2c_data);
int m5602_write_bridge(
- struct sd *sd, u8 address, u8 i2c_data);
+ struct sd *sd, const u8 address, const u8 i2c_data);
int m5602_write_sensor(struct sd *sd, const u8 address,
u8 *i2c_data, const u8 len);
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_core.c b/linux/drivers/media/video/gspca/m5602/m5602_core.c
index b35e4838a..8a5bba16f 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_core.c
@@ -17,6 +17,7 @@
*/
#include "m5602_ov9650.h"
+#include "m5602_ov7660.h"
#include "m5602_mt9m111.h"
#include "m5602_po1030.h"
#include "m5602_s5k83a.h"
@@ -35,7 +36,7 @@ static const __devinitdata struct usb_device_id m5602_table[] = {
MODULE_DEVICE_TABLE(usb, m5602_table);
/* Reads a byte from the m5602 */
-int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
+int m5602_read_bridge(struct sd *sd, const u8 address, u8 *i2c_data)
{
int err;
struct usb_device *udev = sd->gspca_dev.dev;
@@ -51,12 +52,12 @@ int m5602_read_bridge(struct sd *sd, u8 address, u8 *i2c_data)
address, *i2c_data);
/* usb_control_msg(...) returns the number of bytes sent upon success,
- mask that and return zero upon success instead*/
+ mask that and return zero instead*/
return (err < 0) ? err : 0;
}
/* Writes a byte to to the m5602 */
-int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
+int m5602_write_bridge(struct sd *sd, const u8 address, const u8 i2c_data)
{
int err;
struct usb_device *udev = sd->gspca_dev.dev;
@@ -76,10 +77,21 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
4, M5602_URB_MSG_TIMEOUT);
/* usb_control_msg(...) returns the number of bytes sent upon success,
- mask that and return zero upon success instead */
+ mask that and return zero instead */
return (err < 0) ? err : 0;
}
+int m5602_wait_for_i2c(struct sd *sd)
+{
+ int err;
+ u8 data;
+
+ do {
+ err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, &data);
+ } while ((data & I2C_BUSY) && !err);
+ return err;
+}
+
int m5602_read_sensor(struct sd *sd, const u8 address,
u8 *i2c_data, const u8 len)
{
@@ -88,42 +100,43 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
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);
+ err = m5602_wait_for_i2c(sd);
if (err < 0)
- goto out;
+ return err;
err = m5602_write_bridge(sd, M5602_XB_I2C_DEV_ADDR,
sd->sensor->i2c_slave_id);
if (err < 0)
- goto out;
+ return err;
err = m5602_write_bridge(sd, M5602_XB_I2C_REG_ADDR, address);
if (err < 0)
- goto out;
+ return err;
+
+ /* Sensors with registers that are of only
+ one byte width are differently read */
+ /* FIXME: This works with the ov9650, but has issues with the po1030 */
if (sd->sensor->i2c_regW == 1) {
- err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, len);
+ err = m5602_write_bridge(sd, M5602_XB_I2C_CTRL, 1);
if (err < 0)
- goto out;
+ return err;
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_wait_for_i2c(sd);
+ if (err < 0)
+ return err;
+
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;
}
@@ -207,6 +220,11 @@ static int m5602_probe_sensor(struct sd *sd)
if (!sd->sensor->probe(sd))
return 0;
+ /* Try the ov7660 */
+ sd->sensor = &ov7660;
+ if (!sd->sensor->probe(sd))
+ return 0;
+
/* Try the s5k83a */
sd->sensor = &s5k83a;
if (!sd->sensor->probe(sd))
@@ -310,7 +328,11 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
static void m5602_stop_transfer(struct gspca_dev *gspca_dev)
{
- /* Is there are a command to stop a data transfer? */
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* Run the sensor specific end transfer sequence */
+ if (sd->sensor->stop)
+ sd->sensor->stop(sd);
}
/* sub-driver description, the ctrl and nctrl is filled at probe time */
@@ -359,6 +381,17 @@ static int m5602_probe(struct usb_interface *intf,
THIS_MODULE);
}
+void m5602_disconnect(struct usb_interface *intf)
+{
+ struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor->disconnect)
+ sd->sensor->disconnect(sd);
+
+ gspca_disconnect(intf);
+}
+
static struct usb_driver sd_driver = {
.name = MODULE_NAME,
.id_table = m5602_table,
@@ -367,7 +400,7 @@ static struct usb_driver sd_driver = {
.suspend = gspca_suspend,
.resume = gspca_resume,
#endif
- .disconnect = gspca_disconnect
+ .disconnect = m5602_disconnect
};
/* -- module insert / remove -- */
@@ -395,8 +428,9 @@ MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
module_param(force_sensor, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(force_sensor,
- "force detection of sensor, "
- "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, 4 = MT9M111, 5 = PO1030");
+ "forces detection of a sensor, "
+ "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, "
+ "4 = MT9M111, 5 = PO1030, 6 = OV7660");
module_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c
index c0e71c331..8c6d2a229 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.c
@@ -18,12 +18,160 @@
#include "m5602_mt9m111.h"
+static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 val);
+static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 *val);
+static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+
+static struct v4l2_pix_format mt9m111_modes[] = {
+#if 0
+ {
+ 320,
+ 240,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 320 * 240,
+ .bytesperline = 320,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ },
+#endif
+ {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ }
+};
+
+const static struct ctrl mt9m111_ctrls[] = {
+#define VFLIP_IDX 0
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = mt9m111_set_vflip,
+ .get = mt9m111_get_vflip
+ },
+#define HFLIP_IDX 1
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = mt9m111_set_hflip,
+ .get = mt9m111_get_hflip
+ },
+#define GAIN_IDX 2
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0,
+ .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
+ .step = 1,
+ .default_value = MT9M111_DEFAULT_GAIN,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = mt9m111_set_gain,
+ .get = mt9m111_get_gain
+ },
+#define AUTO_WHITE_BALANCE_IDX 3
+ {
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto white balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = mt9m111_set_auto_white_balance,
+ .get = mt9m111_get_auto_white_balance
+ },
+#define GREEN_BALANCE_IDX 4
+ {
+ {
+ .id = M5602_V4L2_CID_GREEN_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "green balance",
+ .minimum = 0x00,
+ .maximum = 0x7ff,
+ .step = 0x1,
+ .default_value = MT9M111_GREEN_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = mt9m111_set_green_balance,
+ .get = mt9m111_get_green_balance
+ },
+#define BLUE_BALANCE_IDX 5
+ {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0x00,
+ .maximum = 0x7ff,
+ .step = 0x1,
+ .default_value = MT9M111_BLUE_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = mt9m111_set_blue_balance,
+ .get = mt9m111_get_blue_balance
+ },
+#define RED_BALANCE_IDX 5
+ {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0x00,
+ .maximum = 0x7ff,
+ .step = 0x1,
+ .default_value = MT9M111_RED_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = mt9m111_set_red_balance,
+ .get = mt9m111_get_red_balance
+ },
+};
+
static void mt9m111_dump_registers(struct sd *sd);
int mt9m111_probe(struct sd *sd)
{
u8 data[2] = {0x00, 0x00};
int i;
+ s32 *sensor_settings;
if (force_sensor) {
if (force_sensor == MT9M111_SENSOR) {
@@ -62,16 +210,27 @@ int mt9m111_probe(struct sd *sd)
return -ENODEV;
sensor_found:
- sd->gspca_dev.cam.cam_mode = mt9m111.modes;
- sd->gspca_dev.cam.nmodes = mt9m111.nmodes;
- sd->desc->ctrls = mt9m111.ctrls;
- sd->desc->nctrls = mt9m111.nctrls;
+ sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32),
+ GFP_KERNEL);
+ if (!sensor_settings)
+ return -ENOMEM;
+
+ sd->gspca_dev.cam.cam_mode = mt9m111_modes;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
+ sd->desc->ctrls = mt9m111_ctrls;
+ sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
+
+ for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++)
+ sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value;
+ sd->sensor_priv = sensor_settings;
+
return 0;
}
int mt9m111_init(struct sd *sd)
{
int i, err = 0;
+ s32 *sensor_settings = sd->sensor_priv;
/* Init the sensor */
for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
@@ -92,119 +251,264 @@ int mt9m111_init(struct sd *sd)
if (dump_sensor)
mt9m111_dump_registers(sd);
- return (err < 0) ? err : 0;
+ err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+ if (err < 0)
+ return err;
+
+ err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+ if (err < 0)
+ return err;
+
+ err = mt9m111_set_green_balance(&sd->gspca_dev,
+ sensor_settings[GREEN_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = mt9m111_set_blue_balance(&sd->gspca_dev,
+ sensor_settings[BLUE_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = mt9m111_set_red_balance(&sd->gspca_dev,
+ sensor_settings[RED_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
}
-int mt9m111_power_down(struct sd *sd)
+int mt9m111_start(struct sd *sd)
{
- return 0;
+ int i, err = 0;
+ u8 data[2];
+ struct cam *cam = &sd->gspca_dev.cam;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1;
+ int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
+
+ for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) {
+ if (start_mt9m111[i][0] == BRIDGE) {
+ err = m5602_write_bridge(sd,
+ start_mt9m111[i][1],
+ start_mt9m111[i][2]);
+ } else {
+ data[0] = start_mt9m111[i][2];
+ data[1] = start_mt9m111[i][3];
+ err = m5602_write_sensor(sd,
+ start_mt9m111[i][1], data, 2);
+ }
+ }
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < 2 && !err; i++)
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < 2 && !err; i++)
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
+ (width >> 8) & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+ if (err < 0)
+ return err;
+
+ switch (width) {
+ case 640:
+ PDEBUG(D_V4L2, "Configuring camera for VGA mode");
+ data[0] = MT9M111_RMB_OVER_SIZED;
+ data[1] = MT9M111_RMB_ROW_SKIP_2X |
+ MT9M111_RMB_COLUMN_SKIP_2X |
+ (sensor_settings[VFLIP_IDX] << 0) |
+ (sensor_settings[HFLIP_IDX] << 1);
+
+ err = m5602_write_sensor(sd,
+ MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+ break;
+
+ case 320:
+ PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
+ data[0] = MT9M111_RMB_OVER_SIZED;
+ data[1] = MT9M111_RMB_ROW_SKIP_4X |
+ MT9M111_RMB_COLUMN_SKIP_4X |
+ (sensor_settings[VFLIP_IDX] << 0) |
+ (sensor_settings[HFLIP_IDX] << 1);
+ err = m5602_write_sensor(sd,
+ MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
+ break;
+ }
+ return err;
}
-int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+void mt9m111_disconnect(struct sd *sd)
+{
+ sd->sensor = NULL;
+ kfree(sd->sensor_priv);
+}
+
+static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
- data, 2);
- *val = data[0] & MT9M111_RMB_MIRROR_ROWS;
+ *val = sensor_settings[VFLIP_IDX];
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
- return err;
+ return 0;
}
-int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
+ sensor_settings[VFLIP_IDX] = val;
+
+ /* The mt9m111 is flipped by default */
+ val = !val;
+
/* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
if (err < 0)
- goto out;
+ return err;
- data[0] = (data[0] & 0xfe) | val;
+ data[1] = (data[1] & 0xfe) | val;
err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
-out:
return err;
}
-int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
- data, 2);
- *val = data[0] & MT9M111_RMB_MIRROR_COLS;
+ *val = sensor_settings[HFLIP_IDX];
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
- return err;
+ return 0;
}
-int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
+ sensor_settings[HFLIP_IDX] = val;
+
+ /* The mt9m111 is flipped by default */
+ val = !val;
+
/* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
- goto out;
+ return err;
err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
if (err < 0)
- goto out;
+ return err;
- data[0] = (data[0] & 0xfd) | ((val << 1) & 0x02);
+ data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02);
err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2);
-out:
return err;
}
-int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err, tmp;
- u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, MT9M111_SC_GLOBAL_GAIN, data, 2);
- tmp = ((data[1] << 8) | data[0]);
+ *val = sensor_settings[GAIN_IDX];
+ PDEBUG(D_V4L2, "Read gain %d", *val);
- *val = ((tmp & (1 << 10)) * 2) |
- ((tmp & (1 << 9)) * 2) |
- ((tmp & (1 << 8)) * 2) |
- (tmp & 0x7f);
+ return 0;
+}
- PDEBUG(D_V4L2, "Read gain %d", *val);
+static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+ int err;
+ u8 data[2];
+ err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
+ if (err < 0)
+ return err;
+
+ sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
+ data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1));
+
+ err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
+
+ PDEBUG(D_V4L2, "Set auto white balance %d", val);
return err;
}
-int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 *val) {
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
+ PDEBUG(D_V4L2, "Read auto white balance %d", *val);
+ return 0;
+}
+
+static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err, tmp;
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ sensor_settings[GAIN_IDX] = val;
/* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
- goto out;
+ return err;
if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2)
return -EINVAL;
@@ -222,17 +526,100 @@ int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
else
tmp = val;
- data[1] = (tmp & 0xff00) >> 8;
- data[0] = (tmp & 0xff);
+ data[1] = (tmp & 0xff);
+ data[0] = (tmp & 0xff00) >> 8;
PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp,
data[1], data[0]);
err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN,
data, 2);
-out:
+
return err;
}
+static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ u8 data[2];
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ sensor_settings[GREEN_BALANCE_IDX] = val;
+ data[1] = (val & 0xff);
+ data[0] = (val & 0xff00) >> 8;
+
+ PDEBUG(D_V4L2, "Set green balance %d", val);
+ err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN,
+ data, 2);
+ if (err < 0)
+ return err;
+
+ return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN,
+ data, 2);
+}
+
+static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[GREEN_BALANCE_IDX];
+ PDEBUG(D_V4L2, "Read green balance %d", *val);
+ return 0;
+}
+
+static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+ u8 data[2];
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ sensor_settings[BLUE_BALANCE_IDX] = val;
+ data[1] = (val & 0xff);
+ data[0] = (val & 0xff00) >> 8;
+
+ PDEBUG(D_V4L2, "Set blue balance %d", val);
+
+ return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN,
+ data, 2);
+}
+
+static int mt9m111_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];
+ PDEBUG(D_V4L2, "Read blue balance %d", *val);
+ return 0;
+}
+
+static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+ u8 data[2];
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ sensor_settings[RED_BALANCE_IDX] = val;
+ data[1] = (val & 0xff);
+ data[0] = (val & 0xff00) >> 8;
+
+ PDEBUG(D_V4L2, "Set red balance %d", val);
+
+ return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN,
+ data, 2);
+}
+
+static int mt9m111_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];
+ PDEBUG(D_V4L2, "Read red balance %d", *val);
+ return 0;
+}
+
static void mt9m111_dump_registers(struct sd *sd)
{
u8 address, value[2] = {0x00, 0x00};
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h
index e795ab7a3..b3de77823 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_mt9m111.h
@@ -37,7 +37,6 @@
#define MT9M111_SC_VBLANK_CONTEXT_A 0x08
#define MT9M111_SC_SHUTTER_WIDTH 0x09
#define MT9M111_SC_ROW_SPEED 0x0a
-
#define MT9M111_SC_EXTRA_DELAY 0x0b
#define MT9M111_SC_SHUTTER_DELAY 0x0c
#define MT9M111_SC_RESET 0x0d
@@ -50,9 +49,6 @@
#define MT9M111_SC_GREEN_2_GAIN 0x2e
#define MT9M111_SC_GLOBAL_GAIN 0x2f
-#define MT9M111_RMB_MIRROR_ROWS (1 << 0)
-#define MT9M111_RMB_MIRROR_COLS (1 << 1)
-
#define MT9M111_CONTEXT_CONTROL 0xc8
#define MT9M111_PAGE_MAP 0xf0
#define MT9M111_BYTEWISE_ADDRESS 0xf1
@@ -74,8 +70,37 @@
#define MT9M111_COLORPIPE 0x01
#define MT9M111_CAMERA_CONTROL 0x02
+#define MT9M111_RESET (1 << 0)
+#define MT9M111_RESTART (1 << 1)
+#define MT9M111_ANALOG_STANDBY (1 << 2)
+#define MT9M111_CHIP_ENABLE (1 << 3)
+#define MT9M111_CHIP_DISABLE (0 << 3)
+#define MT9M111_OUTPUT_DISABLE (1 << 4)
+#define MT9M111_SHOW_BAD_FRAMES (1 << 0)
+#define MT9M111_RESTART_BAD_FRAMES (1 << 1)
+#define MT9M111_SYNCHRONIZE_CHANGES (1 << 7)
+
+#define MT9M111_RMB_OVER_SIZED (1 << 0)
+#define MT9M111_RMB_MIRROR_ROWS (1 << 0)
+#define MT9M111_RMB_MIRROR_COLS (1 << 1)
+#define MT9M111_RMB_ROW_SKIP_2X (1 << 2)
+#define MT9M111_RMB_COLUMN_SKIP_2X (1 << 3)
+#define MT9M111_RMB_ROW_SKIP_4X (1 << 4)
+#define MT9M111_RMB_COLUMN_SKIP_4X (1 << 5)
+
+#define MT9M111_COLOR_MATRIX_BYPASS (1 << 4)
+#define MT9M111_SEL_CONTEXT_B (1 << 3)
+
+#define MT9M111_TRISTATE_PIN_IN_STANDBY (1 << 1)
+#define MT9M111_SOC_SOFT_STANDBY (1 << 0)
+
+#define MT9M111_2D_DEFECT_CORRECTION_ENABLE (1 << 0)
+
#define INITIAL_MAX_GAIN 64
-#define DEFAULT_GAIN 283
+#define MT9M111_DEFAULT_GAIN 283
+#define MT9M111_GREEN_GAIN_DEFAULT 0x20
+#define MT9M111_BLUE_GAIN_DEFAULT 0x20
+#define MT9M111_RED_GAIN_DEFAULT 0x20
/*****************************************************************************/
@@ -85,16 +110,10 @@ extern int dump_sensor;
int mt9m111_probe(struct sd *sd);
int mt9m111_init(struct sd *sd);
-int mt9m111_power_down(struct sd *sd);
+int mt9m111_start(struct sd *sd);
+void mt9m111_disconnect(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);
-int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-
-static struct m5602_sensor mt9m111 = {
+static const struct m5602_sensor mt9m111 = {
.name = "MT9M111",
.i2c_slave_id = 0xba,
@@ -102,64 +121,8 @@ static struct m5602_sensor mt9m111 = {
.probe = mt9m111_probe,
.init = mt9m111_init,
- .power_down = mt9m111_power_down,
-
- .nctrls = 3,
- .ctrls = {
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = mt9m111_set_vflip,
- .get = mt9m111_get_vflip
- }, {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = mt9m111_set_hflip,
- .get = mt9m111_get_hflip
- }, {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0,
- .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
- .step = 1,
- .default_value = DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = mt9m111_set_gain,
- .get = mt9m111_get_gain
- }
- },
-
- .nmodes = 1,
- .modes = {
- {
- M5602_DEFAULT_FRAME_WIDTH,
- M5602_DEFAULT_FRAME_HEIGHT,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
- .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1
- }
- }
+ .disconnect = mt9m111_disconnect,
+ .start = mt9m111_start,
};
static const unsigned char preinit_mt9m111[][4] =
@@ -174,7 +137,14 @@ static const unsigned char preinit_mt9m111[][4] =
{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7},
+ {SENSOR, MT9M111_SC_RESET,
+ MT9M111_RESET |
+ MT9M111_RESTART |
+ MT9M111_ANALOG_STANDBY |
+ MT9M111_CHIP_DISABLE,
+ MT9M111_SHOW_BAD_FRAMES |
+ MT9M111_RESTART_BAD_FRAMES |
+ MT9M111_SYNCHRONIZE_CHANGES},
{BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
{BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
@@ -202,731 +172,42 @@ static const unsigned char init_mt9m111[][4] =
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00},
- {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
{BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
- {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
- {SENSOR, MT9M111_SC_RESET, 0xff, 0xde},
- {SENSOR, MT9M111_SC_RESET, 0xff, 0xff},
- {SENSOR, MT9M111_SC_RESET, 0xff, 0xf7},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
-
- {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0xff, 0xff},
-
- {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
-
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
- {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
- {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
- {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
- {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
- {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
- {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
- {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
- {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
-
- {SENSOR, 0xcd, 0x00, 0x0e},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
- {SENSOR, 0xd0, 0x00, 0x40},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
- {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
- {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
- {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
- {SENSOR, 0x33, 0x03, 0x49},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-
- {SENSOR, 0x33, 0x03, 0x49},
- {SENSOR, 0x34, 0xc0, 0x19},
- {SENSOR, 0x3f, 0x20, 0x20},
- {SENSOR, 0x40, 0x20, 0x20},
- {SENSOR, 0x5a, 0xc0, 0x0a},
- {SENSOR, 0x70, 0x7b, 0x0a},
- {SENSOR, 0x71, 0xff, 0x00},
- {SENSOR, 0x72, 0x19, 0x0e},
- {SENSOR, 0x73, 0x18, 0x0f},
- {SENSOR, 0x74, 0x57, 0x32},
- {SENSOR, 0x75, 0x56, 0x34},
- {SENSOR, 0x76, 0x73, 0x35},
- {SENSOR, 0x77, 0x30, 0x12},
- {SENSOR, 0x78, 0x79, 0x02},
- {SENSOR, 0x79, 0x75, 0x06},
- {SENSOR, 0x7a, 0x77, 0x0a},
- {SENSOR, 0x7b, 0x78, 0x09},
- {SENSOR, 0x7c, 0x7d, 0x06},
- {SENSOR, 0x7d, 0x31, 0x10},
- {SENSOR, 0x7e, 0x00, 0x7e},
- {SENSOR, 0x80, 0x59, 0x04},
- {SENSOR, 0x81, 0x59, 0x04},
- {SENSOR, 0x82, 0x57, 0x0a},
- {SENSOR, 0x83, 0x58, 0x0b},
- {SENSOR, 0x84, 0x47, 0x0c},
- {SENSOR, 0x85, 0x48, 0x0e},
- {SENSOR, 0x86, 0x5b, 0x02},
- {SENSOR, 0x87, 0x00, 0x5c},
- {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
- {SENSOR, 0x60, 0x00, 0x80},
- {SENSOR, 0x61, 0x00, 0x00},
- {SENSOR, 0x62, 0x00, 0x00},
- {SENSOR, 0x63, 0x00, 0x00},
- {SENSOR, 0x64, 0x00, 0x00},
-
- {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
- {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
- {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
- {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
- {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
- {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
- {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
- {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
- {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
- {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
- {SENSOR, 0x30, 0x04, 0x00},
-
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {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, 0x05, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
- {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
-
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {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, 0x05, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
- {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
- {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
{BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
{BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
{BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
-
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
- {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
- {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
- {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
- {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
- {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
- {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
- {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
- {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
- {SENSOR, 0xcd, 0x00, 0x0e},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
- {SENSOR, 0xd0, 0x00, 0x40},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
- {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
- {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
- {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
- {SENSOR, 0x33, 0x03, 0x49},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-
- {SENSOR, 0x33, 0x03, 0x49},
- {SENSOR, 0x34, 0xc0, 0x19},
- {SENSOR, 0x3f, 0x20, 0x20},
- {SENSOR, 0x40, 0x20, 0x20},
- {SENSOR, 0x5a, 0xc0, 0x0a},
- {SENSOR, 0x70, 0x7b, 0x0a},
- {SENSOR, 0x71, 0xff, 0x00},
- {SENSOR, 0x72, 0x19, 0x0e},
- {SENSOR, 0x73, 0x18, 0x0f},
- {SENSOR, 0x74, 0x57, 0x32},
- {SENSOR, 0x75, 0x56, 0x34},
- {SENSOR, 0x76, 0x73, 0x35},
- {SENSOR, 0x77, 0x30, 0x12},
- {SENSOR, 0x78, 0x79, 0x02},
- {SENSOR, 0x79, 0x75, 0x06},
- {SENSOR, 0x7a, 0x77, 0x0a},
- {SENSOR, 0x7b, 0x78, 0x09},
- {SENSOR, 0x7c, 0x7d, 0x06},
- {SENSOR, 0x7d, 0x31, 0x10},
- {SENSOR, 0x7e, 0x00, 0x7e},
- {SENSOR, 0x80, 0x59, 0x04},
- {SENSOR, 0x81, 0x59, 0x04},
- {SENSOR, 0x82, 0x57, 0x0a},
- {SENSOR, 0x83, 0x58, 0x0b},
- {SENSOR, 0x84, 0x47, 0x0c},
- {SENSOR, 0x85, 0x48, 0x0e},
- {SENSOR, 0x86, 0x5b, 0x02},
- {SENSOR, 0x87, 0x00, 0x5c},
- {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
- {SENSOR, 0x60, 0x00, 0x80},
- {SENSOR, 0x61, 0x00, 0x00},
- {SENSOR, 0x62, 0x00, 0x00},
- {SENSOR, 0x63, 0x00, 0x00},
- {SENSOR, 0x64, 0x00, 0x00},
-
- {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
- {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
- {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
- {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
- {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
- {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
- {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
- {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
- {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
- {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
- {SENSOR, 0x30, 0x04, 0x00},
-
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {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, 0x05, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
- {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
-
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
- {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
- {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
{BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
{BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
{SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
{SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
- {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
+ {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00,
+ MT9M111_CP_OPERATING_MODE_CTL},
{SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
- {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
- {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
+ {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00,
+ MT9M111_2D_DEFECT_CORRECTION_ENABLE},
+ {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00,
+ MT9M111_2D_DEFECT_CORRECTION_ENABLE},
{SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
{SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
{SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
{SENSOR, 0xcd, 0x00, 0x0e},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
{SENSOR, 0xd0, 0x00, 0x40},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
- {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
- {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
- {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
- {SENSOR, 0x33, 0x03, 0x49},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
-
- {SENSOR, 0x33, 0x03, 0x49},
- {SENSOR, 0x34, 0xc0, 0x19},
- {SENSOR, 0x3f, 0x20, 0x20},
- {SENSOR, 0x40, 0x20, 0x20},
- {SENSOR, 0x5a, 0xc0, 0x0a},
- {SENSOR, 0x70, 0x7b, 0x0a},
- {SENSOR, 0x71, 0xff, 0x00},
- {SENSOR, 0x72, 0x19, 0x0e},
- {SENSOR, 0x73, 0x18, 0x0f},
- {SENSOR, 0x74, 0x57, 0x32},
- {SENSOR, 0x75, 0x56, 0x34},
- {SENSOR, 0x76, 0x73, 0x35},
- {SENSOR, 0x77, 0x30, 0x12},
- {SENSOR, 0x78, 0x79, 0x02},
- {SENSOR, 0x79, 0x75, 0x06},
- {SENSOR, 0x7a, 0x77, 0x0a},
- {SENSOR, 0x7b, 0x78, 0x09},
- {SENSOR, 0x7c, 0x7d, 0x06},
- {SENSOR, 0x7d, 0x31, 0x10},
- {SENSOR, 0x7e, 0x00, 0x7e},
- {SENSOR, 0x80, 0x59, 0x04},
- {SENSOR, 0x81, 0x59, 0x04},
- {SENSOR, 0x82, 0x57, 0x0a},
- {SENSOR, 0x83, 0x58, 0x0b},
- {SENSOR, 0x84, 0x47, 0x0c},
- {SENSOR, 0x85, 0x48, 0x0e},
- {SENSOR, 0x86, 0x5b, 0x02},
- {SENSOR, 0x87, 0x00, 0x5c},
- {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
- {SENSOR, 0x60, 0x00, 0x80},
- {SENSOR, 0x61, 0x00, 0x00},
- {SENSOR, 0x62, 0x00, 0x00},
- {SENSOR, 0x63, 0x00, 0x00},
- {SENSOR, 0x64, 0x00, 0x00},
- {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
- {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x18},
- {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x04},
- {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x08},
- {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x38},
- {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
- {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x38},
- {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
- {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x03},
- {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x03},
- {SENSOR, 0x30, 0x04, 0x00},
-
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x07, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0xf4},
- {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xea},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
- {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
- {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
- {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
- {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
- {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
- {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
- {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
- {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
- {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, 0xcd, 0x00, 0x0e},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, 0xd0, 0x00, 0x40},
{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
{SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
{SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, 0x33, 0x03, 0x49},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-
- {SENSOR, 0x33, 0x03, 0x49},
- {SENSOR, 0x34, 0xc0, 0x19},
- {SENSOR, 0x3f, 0x20, 0x20},
- {SENSOR, 0x40, 0x20, 0x20},
- {SENSOR, 0x5a, 0xc0, 0x0a},
- {SENSOR, 0x70, 0x7b, 0x0a},
- {SENSOR, 0x71, 0xff, 0x00},
- {SENSOR, 0x72, 0x19, 0x0e},
- {SENSOR, 0x73, 0x18, 0x0f},
- {SENSOR, 0x74, 0x57, 0x32},
- {SENSOR, 0x75, 0x56, 0x34},
- {SENSOR, 0x76, 0x73, 0x35},
- {SENSOR, 0x77, 0x30, 0x12},
- {SENSOR, 0x78, 0x79, 0x02},
- {SENSOR, 0x79, 0x75, 0x06},
- {SENSOR, 0x7a, 0x77, 0x0a},
- {SENSOR, 0x7b, 0x78, 0x09},
- {SENSOR, 0x7c, 0x7d, 0x06},
- {SENSOR, 0x7d, 0x31, 0x10},
- {SENSOR, 0x7e, 0x00, 0x7e},
- {SENSOR, 0x80, 0x59, 0x04},
- {SENSOR, 0x81, 0x59, 0x04},
- {SENSOR, 0x82, 0x57, 0x0a},
- {SENSOR, 0x83, 0x58, 0x0b},
- {SENSOR, 0x84, 0x47, 0x0c},
- {SENSOR, 0x85, 0x48, 0x0e},
- {SENSOR, 0x86, 0x5b, 0x02},
- {SENSOR, 0x87, 0x00, 0x5c},
- {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
- {SENSOR, 0x60, 0x00, 0x80},
- {SENSOR, 0x61, 0x00, 0x00},
- {SENSOR, 0x62, 0x00, 0x00},
- {SENSOR, 0x63, 0x00, 0x00},
- {SENSOR, 0x64, 0x00, 0x00},
- {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
- {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12},
- {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00},
- {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10},
- {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60},
- {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
- {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60},
- {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
- {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f},
- {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f},
- {SENSOR, 0x30, 0x04, 0x00},
-
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xe3, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {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, 0x87, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
- {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x00, 0xe6},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x09},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x0c},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x04},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xb3, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_CP_GLOBAL_CLK_CONTROL, 0x00, 0x03},
- {BRIDGE, M5602_XB_GPIO_DIR, 0x05, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x04, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x3e, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3e, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR, 0x07, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x0b, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x05},
{SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x29},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x0d, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_SC_RESET, 0x00, 0x08},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x01},
- {SENSOR, MT9M111_CP_OPERATING_MODE_CTL, 0x00, 0x10},
- {SENSOR, MT9M111_CP_LENS_CORRECTION_1, 0x04, 0x2a},
- {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_A, 0x00, 0x01},
- {SENSOR, MT9M111_CP_DEFECT_CORR_CONTEXT_B, 0x00, 0x01},
- {SENSOR, MT9M111_CP_LUMA_OFFSET, 0x00, 0x00},
- {SENSOR, MT9M111_CP_LUMA_CLIP, 0xff, 0x00},
- {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_A, 0x14, 0x00},
- {SENSOR, MT9M111_CP_OUTPUT_FORMAT_CTL2_CONTEXT_B, 0x14, 0x00},
-
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xcd, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, 0xcd, 0x00, 0x0e},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0xd0, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, 0xd0, 0x00, 0x40},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x02},
- {SENSOR, MT9M111_CC_AUTO_EXPOSURE_PARAMETER_18, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x07},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x28, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, MT9M111_CC_AWB_PARAMETER_7, 0xef, 0x03},
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
-
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
- {SENSOR, 0x33, 0x03, 0x49},
- {BRIDGE, M5602_XB_I2C_DEV_ADDR, 0xba, 0x00},
- {BRIDGE, M5602_XB_I2C_REG_ADDR, 0x33, 0x00},
- {BRIDGE, M5602_XB_I2C_CTRL, 0x1a, 0x00},
-
{SENSOR, 0x33, 0x03, 0x49},
{SENSOR, 0x34, 0xc0, 0x19},
{SENSOR, 0x3f, 0x20, 0x20},
@@ -955,25 +236,29 @@ static const unsigned char init_mt9m111[][4] =
{SENSOR, 0x85, 0x48, 0x0e},
{SENSOR, 0x86, 0x5b, 0x02},
{SENSOR, 0x87, 0x00, 0x5c},
- {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, 0x08},
+ {SENSOR, MT9M111_CONTEXT_CONTROL, 0x00, MT9M111_SEL_CONTEXT_B},
{SENSOR, 0x60, 0x00, 0x80},
{SENSOR, 0x61, 0x00, 0x00},
{SENSOR, 0x62, 0x00, 0x00},
{SENSOR, 0x63, 0x00, 0x00},
{SENSOR, 0x64, 0x00, 0x00},
- {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d},
- {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12},
- {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00},
- {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10},
- {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60},
- {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11},
- {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60},
- {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11},
- {SENSOR, MT9M111_SC_R_MODE_CONTEXT_B, 0x01, 0x0f},
- {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f},
+ {SENSOR, MT9M111_SC_ROWSTART, 0x00, 0x0d}, /* 13 */
+ {SENSOR, MT9M111_SC_COLSTART, 0x00, 0x12}, /* 18 */
+ {SENSOR, MT9M111_SC_WINDOW_HEIGHT, 0x04, 0x00}, /* 1024 */
+ {SENSOR, MT9M111_SC_WINDOW_WIDTH, 0x05, 0x10}, /* 1296 */
+ {SENSOR, MT9M111_SC_HBLANK_CONTEXT_B, 0x01, 0x60}, /* 352 */
+ {SENSOR, MT9M111_SC_VBLANK_CONTEXT_B, 0x00, 0x11}, /* 17 */
+ {SENSOR, MT9M111_SC_HBLANK_CONTEXT_A, 0x01, 0x60}, /* 352 */
+ {SENSOR, MT9M111_SC_VBLANK_CONTEXT_A, 0x00, 0x11}, /* 17 */
+ {SENSOR, MT9M111_SC_R_MODE_CONTEXT_A, 0x01, 0x0f}, /* 271 */
{SENSOR, 0x30, 0x04, 0x00},
+ /* Set number of blank rows chosen to 400 */
+ {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
+};
+static const unsigned char start_mt9m111[][4] =
+{
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -985,25 +270,6 @@ static const unsigned char init_mt9m111[][4] =
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {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}, /* 639*/
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
- {SENSOR, MT9M111_PAGE_MAP, 0x00, 0x00},
- /* Set number of blank rows chosen to 400 */
- {SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
- /* Set the global gain to 283 (of 512) */
- {SENSOR, MT9M111_SC_GLOBAL_GAIN, 0x03, 0x63}
};
#endif
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov7660.c b/linux/drivers/media/video/gspca/m5602/m5602_ov7660.c
new file mode 100644
index 000000000..7aafeb7cf
--- /dev/null
+++ b/linux/drivers/media/video/gspca/m5602/m5602_ov7660.c
@@ -0,0 +1,227 @@
+/*
+ * Driver for the ov7660 sensor
+ *
+ * Copyright (C) 2009 Erik Andrén
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#include "m5602_ov7660.h"
+
+static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+
+const static struct ctrl ov7660_ctrls[] = {
+#define GAIN_IDX 1
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = OV7660_DEFAULT_GAIN,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = ov7660_set_gain,
+ .get = ov7660_get_gain
+ },
+};
+
+static struct v4l2_pix_format ov7660_modes[] = {
+ {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ }
+};
+
+static void ov7660_dump_registers(struct sd *sd);
+
+int ov7660_probe(struct sd *sd)
+{
+ int err = 0, i;
+ u8 prod_id = 0, ver_id = 0;
+
+ s32 *sensor_settings;
+
+ if (force_sensor) {
+ if (force_sensor == OV7660_SENSOR) {
+ info("Forcing an %s sensor", ov7660.name);
+ goto sensor_found;
+ }
+ /* If we want to force another sensor,
+ don't try to probe this one */
+ return -ENODEV;
+ }
+
+ /* Do the preinit */
+ for (i = 0; i < ARRAY_SIZE(preinit_ov7660) && !err; i++) {
+ u8 data[2];
+
+ if (preinit_ov7660[i][0] == BRIDGE) {
+ err = m5602_write_bridge(sd,
+ preinit_ov7660[i][1],
+ preinit_ov7660[i][2]);
+ } else {
+ data[0] = preinit_ov7660[i][2];
+ err = m5602_write_sensor(sd,
+ preinit_ov7660[i][1], data, 1);
+ }
+ }
+ if (err < 0)
+ return err;
+
+ if (m5602_read_sensor(sd, OV7660_PID, &prod_id, 1))
+ return -ENODEV;
+
+ if (m5602_read_sensor(sd, OV7660_VER, &ver_id, 1))
+ return -ENODEV;
+
+ info("Sensor reported 0x%x%x", prod_id, ver_id);
+
+ if ((prod_id == 0x76) && (ver_id == 0x60)) {
+ info("Detected a ov7660 sensor");
+ goto sensor_found;
+ }
+ return -ENODEV;
+
+sensor_found:
+ sensor_settings = kmalloc(
+ ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
+ if (!sensor_settings)
+ return -ENOMEM;
+
+ sd->gspca_dev.cam.cam_mode = ov7660_modes;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
+ sd->desc->ctrls = ov7660_ctrls;
+ sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
+
+ for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
+ sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
+ sd->sensor_priv = sensor_settings;
+
+ return 0;
+}
+
+int ov7660_init(struct sd *sd)
+{
+ int i, err = 0;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ /* Init the sensor */
+ for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
+ u8 data[2];
+
+ if (init_ov7660[i][0] == BRIDGE) {
+ err = m5602_write_bridge(sd,
+ init_ov7660[i][1],
+ init_ov7660[i][2]);
+ } else {
+ data[0] = init_ov7660[i][2];
+ err = m5602_write_sensor(sd,
+ init_ov7660[i][1], data, 1);
+ }
+ }
+
+ if (dump_sensor)
+ ov7660_dump_registers(sd);
+
+ err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+ if (err < 0)
+ return err;
+
+ return err;
+}
+
+int ov7660_start(struct sd *sd)
+{
+ return 0;
+}
+
+int ov7660_stop(struct sd *sd)
+{
+ return 0;
+}
+
+void ov7660_disconnect(struct sd *sd)
+{
+ ov7660_stop(sd);
+
+ sd->sensor = NULL;
+ kfree(sd->sensor_priv);
+}
+
+static int ov7660_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];
+ PDEBUG(D_V4L2, "Read gain %d", *val);
+ return 0;
+}
+
+static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ u8 i2c_data;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ PDEBUG(D_V4L2, "Setting gain to %d", val);
+
+ sensor_settings[GAIN_IDX] = val;
+
+ err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
+ return err;
+}
+
+static void ov7660_dump_registers(struct sd *sd)
+{
+ int address;
+ info("Dumping the ov7660 register state");
+ for (address = 0; address < 0xa9; address++) {
+ u8 value;
+ m5602_read_sensor(sd, address, &value, 1);
+ info("register 0x%x contains 0x%x",
+ address, value);
+ }
+
+ info("ov7660 register state dump complete");
+
+ info("Probing for which registers that are read/write");
+ for (address = 0; address < 0xff; address++) {
+ u8 old_value, ctrl_value;
+ u8 test_value[2] = {0xff, 0xff};
+
+ 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);
+ else
+ info("register 0x%x is read only", address);
+
+ /* Restore original value */
+ m5602_write_sensor(sd, address, &old_value, 1);
+ }
+}
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov7660.h b/linux/drivers/media/video/gspca/m5602/m5602_ov7660.h
new file mode 100644
index 000000000..3f2c169a9
--- /dev/null
+++ b/linux/drivers/media/video/gspca/m5602/m5602_ov7660.h
@@ -0,0 +1,279 @@
+/*
+ * Driver for the ov7660 sensor
+ *
+ * Copyright (C) 2009 Erik Andrén
+ * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.
+ * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br>
+ *
+ * Portions of code to USB interface and ALi driver software,
+ * Copyright (c) 2006 Willem Duinker
+ * v4l2 interface modeled after the V4L2 driver
+ * for SN9C10x PC Camera Controllers
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ *
+ */
+
+#ifndef M5602_OV7660_H_
+#define M5602_OV7660_H_
+
+#include "m5602_sensor.h"
+
+#define OV7660_GAIN 0x00
+#define OV7660_BLUE_GAIN 0x01
+#define OV7660_RED_GAIN 0x02
+#define OV7660_VREF 0x03
+#define OV7660_COM1 0x04
+#define OV7660_BAVE 0x05
+#define OV7660_GEAVE 0x06
+#define OV7660_AECHH 0x07
+#define OV7660_RAVE 0x08
+#define OV7660_COM2 0x09
+#define OV7660_PID 0x0a
+#define OV7660_VER 0x0b
+#define OV7660_COM3 0x0c
+#define OV7660_COM4 0x0d
+#define OV7660_COM5 0x0e
+#define OV7660_COM6 0x0f
+#define OV7660_AECH 0x10
+#define OV7660_CLKRC 0x11
+#define OV7660_COM7 0x12
+#define OV7660_COM8 0x13
+#define OV7660_COM9 0x14
+#define OV7660_COM10 0x15
+#define OV7660_RSVD16 0x16
+#define OV7660_HSTART 0x17
+#define OV7660_HSTOP 0x18
+#define OV7660_VSTART 0x19
+#define OV7660_VSTOP 0x1a
+#define OV7660_PSHFT 0x1b
+#define OV7660_MIDH 0x1c
+#define OV7660_MIDL 0x1d
+#define OV7660_MVFP 0x1e
+#define OV7660_LAEC 0x1f
+#define OV7660_BOS 0x20
+#define OV7660_GBOS 0x21
+#define OV7660_GROS 0x22
+#define OV7660_ROS 0x23
+#define OV7660_AEW 0x24
+#define OV7660_AEB 0x25
+#define OV7660_VPT 0x26
+#define OV7660_BBIAS 0x27
+#define OV7660_GbBIAS 0x28
+#define OV7660_RSVD29 0x29
+#define OV7660_RBIAS 0x2c
+#define OV7660_HREF 0x32
+#define OV7660_ADC 0x37
+#define OV7660_OFON 0x39
+#define OV7660_TSLB 0x3a
+#define OV7660_COM12 0x3c
+#define OV7660_COM13 0x3d
+#define OV7660_LCC1 0x62
+#define OV7660_LCC2 0x63
+#define OV7660_LCC3 0x64
+#define OV7660_LCC4 0x65
+#define OV7660_LCC5 0x66
+#define OV7660_HV 0x69
+#define OV7660_RSVDA1 0xa1
+
+#define OV7660_DEFAULT_GAIN 0x0e
+#define OV7660_DEFAULT_RED_GAIN 0x80
+#define OV7660_DEFAULT_BLUE_GAIN 0x80
+#define OV7660_DEFAULT_SATURATION 0x00
+#define OV7660_DEFAULT_EXPOSURE 0x20
+
+/* Kernel module parameters */
+extern int force_sensor;
+extern int dump_sensor;
+
+int ov7660_probe(struct sd *sd);
+int ov7660_init(struct sd *sd);
+int ov7660_start(struct sd *sd);
+int ov7660_stop(struct sd *sd);
+void ov7660_disconnect(struct sd *sd);
+
+const static struct m5602_sensor ov7660 = {
+ .name = "ov7660",
+ .i2c_slave_id = 0x42,
+ .i2c_regW = 1,
+ .probe = ov7660_probe,
+ .init = ov7660_init,
+ .start = ov7660_start,
+ .stop = ov7660_stop,
+ .disconnect = ov7660_disconnect,
+};
+
+static const unsigned char preinit_ov7660[][4] =
+{
+ {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+ {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+ {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+ {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
+ {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+ {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+ {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+
+ {SENSOR, OV7660_OFON, 0x0c},
+ {SENSOR, OV7660_COM2, 0x11},
+ {SENSOR, OV7660_COM7, 0x05},
+
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+ {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+ {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+ {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+ {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+ {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+ {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_EN_L, 0x00}
+};
+
+static const unsigned char init_ov7660[][4] =
+{
+ {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
+ {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+ {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+ {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
+ {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x03},
+ {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+ {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+
+ {SENSOR, OV7660_OFON, 0x0c},
+ {SENSOR, OV7660_COM2, 0x11},
+ {SENSOR, OV7660_COM7, 0x05},
+
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+ {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+ {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+ {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+ {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+ {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+ {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
+
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x02},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+
+ {SENSOR, OV7660_AECH, OV7660_DEFAULT_EXPOSURE},
+ {SENSOR, OV7660_COM1, 0x00},
+
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+ {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+ {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+ {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+ {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+ {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+ {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
+
+ {SENSOR, OV7660_COM7, 0x80},
+ {SENSOR, OV7660_CLKRC, 0x80},
+ {SENSOR, OV7660_BLUE_GAIN, 0x80},
+ {SENSOR, OV7660_RED_GAIN, 0x80},
+ {SENSOR, OV7660_COM9, 0x4c},
+ {SENSOR, OV7660_OFON, 0x43},
+ {SENSOR, OV7660_COM12, 0x28},
+ {SENSOR, OV7660_COM8, 0x00},
+ {SENSOR, OV7660_COM10, 0x40},
+ {SENSOR, OV7660_HSTART, 0x0c},
+ {SENSOR, OV7660_HSTOP, 0x61},
+ {SENSOR, OV7660_HREF, 0xa4},
+ {SENSOR, OV7660_PSHFT, 0x0b},
+ {SENSOR, OV7660_VSTART, 0x01},
+ {SENSOR, OV7660_VSTOP, 0x7a},
+ {SENSOR, OV7660_VREF, 0x00},
+ {SENSOR, OV7660_COM7, 0x05},
+ {SENSOR, OV7660_COM6, 0x4b},
+ {SENSOR, OV7660_BBIAS, 0x98},
+ {SENSOR, OV7660_GbBIAS, 0x98},
+ {SENSOR, OV7660_RSVD29, 0x98},
+ {SENSOR, OV7660_RBIAS, 0x98},
+ {SENSOR, OV7660_COM1, 0x00},
+ {SENSOR, OV7660_AECH, 0x00},
+ {SENSOR, OV7660_AECHH, 0x00},
+ {SENSOR, OV7660_ADC, 0x04},
+ {SENSOR, OV7660_COM13, 0x00},
+ {SENSOR, OV7660_RSVDA1, 0x23},
+ {SENSOR, OV7660_TSLB, 0x0d},
+ {SENSOR, OV7660_HV, 0x80},
+ {SENSOR, OV7660_LCC1, 0x00},
+ {SENSOR, OV7660_LCC2, 0x00},
+ {SENSOR, OV7660_LCC3, 0x10},
+ {SENSOR, OV7660_LCC4, 0x40},
+ {SENSOR, OV7660_LCC5, 0x01},
+
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+ {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
+ {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
+ {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
+ {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
+ {BRIDGE, M5602_XB_SIG_INI, 0x01},
+ {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, 0x01},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0xe0}, /* 480 */
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_SIG_INI, 0x00},
+ {BRIDGE, M5602_XB_SIG_INI, 0x02},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x27}, /* 39 */
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0xa7}, /* 679 */
+ {BRIDGE, M5602_XB_SIG_INI, 0x00},
+
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
+
+ {SENSOR, OV7660_AECH, 0x20},
+ {SENSOR, OV7660_COM1, 0x00},
+ {SENSOR, OV7660_OFON, 0x0c},
+ {SENSOR, OV7660_COM2, 0x11},
+ {SENSOR, OV7660_COM7, 0x05},
+ {SENSOR, OV7660_BLUE_GAIN, 0x80},
+ {SENSOR, OV7660_RED_GAIN, 0x80},
+
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x01},
+ {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
+ {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x08},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0}
+};
+
+#endif
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c
index dde5075ed..bbf9935df 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.c
@@ -18,6 +18,27 @@
#include "m5602_ov9650.h"
+static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 *val);
+static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 val);
+static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
+
/* Vertically and horizontally flips the image if matched, needed for machines
where the sensor is mounted upside down */
static
@@ -26,6 +47,14 @@ static
#endif
struct dmi_system_id ov9650_flip_dmi_table[] = {
{
+ .ident = "ASUS A6VA",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "A6VA")
+ }
+ },
+ {
+
.ident = "ASUS A6VC",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
@@ -61,20 +90,207 @@ static
}
},
{
+ .ident = "ASUS A6K",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "A6K")
+ }
+ },
+ {
.ident = "Alienware Aurora m9700",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "alienware"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aurora m9700")
}
},
- { }
+ {}
+};
+
+static const struct ctrl ov9650_ctrls[] = {
+#define EXPOSURE_IDX 0
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x00,
+ .maximum = 0x1ff,
+ .step = 0x4,
+ .default_value = EXPOSURE_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = ov9650_set_exposure,
+ .get = ov9650_get_exposure
+ },
+#define GAIN_IDX 1
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0x00,
+ .maximum = 0x3ff,
+ .step = 0x1,
+ .default_value = GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = ov9650_set_gain,
+ .get = ov9650_get_gain
+ },
+#define RED_BALANCE_IDX 2
+ {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = RED_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = ov9650_set_red_balance,
+ .get = ov9650_get_red_balance
+ },
+#define BLUE_BALANCE_IDX 3
+ {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = BLUE_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = ov9650_set_blue_balance,
+ .get = ov9650_get_blue_balance
+ },
+#define HFLIP_IDX 4
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = ov9650_set_hflip,
+ .get = ov9650_get_hflip
+ },
+#define VFLIP_IDX 5
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = ov9650_set_vflip,
+ .get = ov9650_get_vflip
+ },
+#define AUTO_WHITE_BALANCE_IDX 6
+ {
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto white balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
+ },
+ .set = ov9650_set_auto_white_balance,
+ .get = ov9650_get_auto_white_balance
+ },
+#define AUTO_GAIN_CTRL_IDX 7
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto gain control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
+ },
+ .set = ov9650_set_auto_gain,
+ .get = ov9650_get_auto_gain
+ },
+#define AUTO_EXPOSURE_IDX 8
+ {
+ {
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
+ },
+ .set = ov9650_set_auto_exposure,
+ .get = ov9650_get_auto_exposure
+ }
+
+};
+
+static struct v4l2_pix_format ov9650_modes[] = {
+ {
+ 176,
+ 144,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 176 * 144,
+ .bytesperline = 176,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 9
+ }, {
+ 320,
+ 240,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 320 * 240,
+ .bytesperline = 320,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 8
+ }, {
+ 352,
+ 288,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 352 * 288,
+ .bytesperline = 352,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 9
+ }, {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 9
+ }
};
static void ov9650_dump_registers(struct sd *sd);
int ov9650_probe(struct sd *sd)
{
+ int err = 0;
u8 prod_id = 0, ver_id = 0, i;
+ s32 *sensor_settings;
if (force_sensor) {
if (force_sensor == OV9650_SENSOR) {
@@ -88,16 +304,20 @@ int ov9650_probe(struct sd *sd)
info("Probing for an ov9650 sensor");
- /* Run the pre-init to actually probe the unit */
- for (i = 0; i < ARRAY_SIZE(preinit_ov9650); i++) {
+ /* Run the pre-init before probing the sensor */
+ for (i = 0; i < ARRAY_SIZE(preinit_ov9650) && !err; i++) {
u8 data = preinit_ov9650[i][2];
if (preinit_ov9650[i][0] == SENSOR)
- m5602_write_sensor(sd,
- preinit_ov9650[i][1], &data, 1);
+ err = m5602_write_sensor(sd,
+ preinit_ov9650[i][1], &data, 1);
else
- m5602_write_bridge(sd, preinit_ov9650[i][1], data);
+ err = m5602_write_bridge(sd,
+ preinit_ov9650[i][1], data);
}
+ if (err < 0)
+ return err;
+
if (m5602_read_sensor(sd, OV9650_PID, &prod_id, 1))
return -ENODEV;
@@ -108,14 +328,22 @@ int ov9650_probe(struct sd *sd)
info("Detected an ov9650 sensor");
goto sensor_found;
}
-
return -ENODEV;
sensor_found:
- sd->gspca_dev.cam.cam_mode = ov9650.modes;
- sd->gspca_dev.cam.nmodes = ov9650.nmodes;
- sd->desc->ctrls = ov9650.ctrls;
- sd->desc->nctrls = ov9650.nctrls;
+ sensor_settings = kmalloc(
+ ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
+ if (!sensor_settings)
+ return -ENOMEM;
+
+ sd->gspca_dev.cam.cam_mode = ov9650_modes;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
+ sd->desc->ctrls = ov9650_ctrls;
+ sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
+
+ for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
+ sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
+ sd->sensor_priv = sensor_settings;
return 0;
}
@@ -123,6 +351,7 @@ int ov9650_init(struct sd *sd)
{
int i, err = 0;
u8 data;
+ s32 *sensor_settings = sd->sensor_priv;
if (dump_sensor)
ov9650_dump_registers(sd);
@@ -136,172 +365,264 @@ int ov9650_init(struct sd *sd)
err = m5602_write_bridge(sd, init_ov9650[i][1], data);
}
- if (dmi_check_system(ov9650_flip_dmi_table) && !err) {
- info("vflip quirk active");
- data = 0x30;
- err = m5602_write_sensor(sd, OV9650_MVFP, &data, 1);
- }
+ err = ov9650_set_exposure(&sd->gspca_dev,
+ sensor_settings[EXPOSURE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_red_balance(&sd->gspca_dev,
+ sensor_settings[RED_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_blue_balance(&sd->gspca_dev,
+ sensor_settings[BLUE_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_auto_exposure(&sd->gspca_dev,
+ sensor_settings[AUTO_EXPOSURE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_auto_white_balance(&sd->gspca_dev,
+ sensor_settings[AUTO_WHITE_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = ov9650_set_auto_gain(&sd->gspca_dev,
+ sensor_settings[AUTO_GAIN_CTRL_IDX]);
return err;
}
int ov9650_start(struct sd *sd)
{
+ u8 data;
int i, err = 0;
struct cam *cam = &sd->gspca_dev.cam;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
+ int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
+ int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
+ int hor_offs = OV9650_LEFT_OFFSET;
+
+ if ((!dmi_check_system(ov9650_flip_dmi_table) &&
+ sensor_settings[VFLIP_IDX]) ||
+ (dmi_check_system(ov9650_flip_dmi_table) &&
+ !sensor_settings[VFLIP_IDX]))
+ ver_offs--;
+ if (width <= 320)
+ hor_offs /= 2;
+
+ /* Synthesize the vsync/hsync setup */
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 (res_init_ov9650[i][0] == BRIDGE)
+ err = m5602_write_bridge(sd, res_init_ov9650[i][1],
+ res_init_ov9650[i][2]);
+ else if (res_init_ov9650[i][0] == SENSOR) {
+ u8 data = res_init_ov9650[i][2];
+ err = m5602_write_sensor(sd,
+ res_init_ov9650[i][1], &data, 1);
+ }
}
if (err < 0)
return err;
- switch (cam->cam_mode[sd->gspca_dev.curr_mode].width)
- {
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
+ ((ver_offs >> 8) & 0xff));
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < 2 && !err; i++)
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
+ (hor_offs >> 8) & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, hor_offs & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
+ ((width + hor_offs) >> 8) & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA,
+ ((width + hor_offs) & 0xff));
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+ if (err < 0)
+ return err;
+
+ switch (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);
- }
+ data = OV9650_VGA_SELECT | OV9650_RGB_SELECT |
+ OV9650_RAW_RGB_SELECT;
+ err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
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);
- }
+ data = OV9650_CIF_SELECT | OV9650_RGB_SELECT |
+ OV9650_RAW_RGB_SELECT;
+ err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
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);
- }
+ data = OV9650_QVGA_SELECT | OV9650_RGB_SELECT |
+ OV9650_RAW_RGB_SELECT;
+ err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
+ break;
+
+ case 176:
+ PDEBUG(D_V4L2, "Configuring camera for QCIF mode");
+
+ data = OV9650_QCIF_SELECT | OV9650_RGB_SELECT |
+ OV9650_RAW_RGB_SELECT;
+ err = m5602_write_sensor(sd, OV9650_COM7, &data, 1);
break;
}
return err;
}
-int ov9650_power_down(struct sd *sd)
+int ov9650_stop(struct sd *sd)
{
- 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)
- err = m5602_write_sensor(sd,
- power_down_ov9650[i][1], &data, 1);
- else
- err = m5602_write_bridge(sd, power_down_ov9650[i][1],
- data);
- }
-
- return err;
+ u8 data = OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X;
+ return m5602_write_sensor(sd, OV9650_COM2, &data, 1);
}
-int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+void ov9650_disconnect(struct sd *sd)
{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 i2c_data;
- int err;
+ ov9650_stop(sd);
- err = m5602_read_sensor(sd, OV9650_COM1, &i2c_data, 1);
- if (err < 0)
- goto out;
- *val = i2c_data & 0x03;
-
- err = m5602_read_sensor(sd, OV9650_AECH, &i2c_data, 1);
- if (err < 0)
- goto out;
- *val |= (i2c_data << 2);
+ sd->sensor = NULL;
+ kfree(sd->sensor_priv);
+}
- err = m5602_read_sensor(sd, OV9650_AECHM, &i2c_data, 1);
- if (err < 0)
- goto out;
- *val |= (i2c_data & 0x3f) << 10;
+static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+ *val = sensor_settings[EXPOSURE_IDX];
PDEBUG(D_V4L2, "Read exposure %d", *val);
-out:
- return err;
+ return 0;
}
-int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- PDEBUG(D_V4L2, "Set exposure to %d",
- val & 0xffff);
+ PDEBUG(D_V4L2, "Set exposure to %d", val);
+ sensor_settings[EXPOSURE_IDX] = val;
/* The 6 MSBs */
i2c_data = (val >> 10) & 0x3f;
err = m5602_write_sensor(sd, OV9650_AECHM,
&i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
/* The 8 middle bits */
i2c_data = (val >> 2) & 0xff;
err = m5602_write_sensor(sd, OV9650_AECH,
&i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
/* The 2 LSBs */
i2c_data = val & 0x03;
err = m5602_write_sensor(sd, OV9650_COM1, &i2c_data, 1);
-
-out:
return err;
}
-int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
- *val = (i2c_data & 0x03) << 8;
-
- err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
- *val |= i2c_data;
+ *val = sensor_settings[GAIN_IDX];
PDEBUG(D_V4L2, "Read gain %d", *val);
- return err;
+ return 0;
}
-int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ PDEBUG(D_V4L2, "Setting gain to %d", val);
+
+ sensor_settings[GAIN_IDX] = val;
/* The 2 MSB */
/* Read the OV9650_VREF register first to avoid
corrupting the VREF high and low bits */
- m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ if (err < 0)
+ return err;
+
/* Mask away all uninteresting bits */
i2c_data = ((val & 0x0300) >> 2) |
(i2c_data & 0x3F);
err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ if (err < 0)
+ return err;
/* The 8 LSBs */
i2c_data = val & 0xff;
@@ -309,246 +630,216 @@ int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
return err;
}
-int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, OV9650_RED, &i2c_data, 1);
- *val = i2c_data;
-
+ *val = sensor_settings[RED_BALANCE_IDX];
PDEBUG(D_V4L2, "Read red gain %d", *val);
-
- return err;
+ return 0;
}
-int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ PDEBUG(D_V4L2, "Set red gain to %d", val);
- PDEBUG(D_V4L2, "Set red gain to %d",
- val & 0xff);
+ sensor_settings[RED_BALANCE_IDX] = val;
i2c_data = val & 0xff;
err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
-
return err;
}
-int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, OV9650_BLUE, &i2c_data, 1);
- *val = i2c_data;
-
+ *val = sensor_settings[BLUE_BALANCE_IDX];
PDEBUG(D_V4L2, "Read blue gain %d", *val);
- return err;
+ return 0;
}
-int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ PDEBUG(D_V4L2, "Set blue gain to %d", val);
- PDEBUG(D_V4L2, "Set blue gain to %d",
- val & 0xff);
+ sensor_settings[BLUE_BALANCE_IDX] = val;
i2c_data = val & 0xff;
err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
-
return err;
}
-int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- 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;
+ *val = sensor_settings[HFLIP_IDX];
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-
- return err;
+ return 0;
}
-int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
- 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));
+ sensor_settings[HFLIP_IDX] = val;
+
+ if (!dmi_check_system(ov9650_flip_dmi_table))
+ i2c_data = ((val & 0x01) << 5) |
+ (sensor_settings[VFLIP_IDX] << 4);
else
- i2c_data = ((i2c_data & 0xdf) |
- ((val & 0x01) << 5));
+ i2c_data = ((val & 0x01) << 5) |
+ (!sensor_settings[VFLIP_IDX] << 4);
err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
-out:
+
return err;
}
-int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- 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;
+ *val = sensor_settings[VFLIP_IDX];
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
- return err;
+ return 0;
}
-int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
- err = m5602_read_sensor(sd, OV9650_MVFP, &i2c_data, 1);
- if (err < 0)
- goto out;
+ sensor_settings[VFLIP_IDX] = val;
if (dmi_check_system(ov9650_flip_dmi_table))
- i2c_data = ((i2c_data & 0xef) |
- (((val ? 0 : 1) & 0x01) << 4));
- else
- i2c_data = ((i2c_data & 0xef) |
- ((val & 0x01) << 4));
+ val = !val;
+ i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
-out:
+ if (err < 0)
+ return err;
+
+ /* When vflip is toggled we need to readjust the bridge hsync/vsync */
+ if (gspca_dev->streaming)
+ err = ov9650_start(sd);
+
return err;
}
-int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
- if (err < 0)
- goto out;
- *val = (i2c_data & 0x03) << 8;
-
- err = m5602_read_sensor(sd, OV9650_GAIN, &i2c_data, 1);
- *val |= i2c_data;
- PDEBUG(D_V4L2, "Read gain %d", *val);
-out:
- return err;
+ *val = sensor_settings[AUTO_EXPOSURE_IDX];
+ PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
+ return 0;
}
-int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
+ __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- PDEBUG(D_V4L2, "Set gain to %d", val & 0x3ff);
-
- /* Read the OV9650_VREF register first to avoid
- corrupting the VREF high and low bits */
- err = m5602_read_sensor(sd, OV9650_VREF, &i2c_data, 1);
- if (err < 0)
- goto out;
+ PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
- /* Mask away all uninteresting bits */
- i2c_data = ((val & 0x0300) >> 2) | (i2c_data & 0x3F);
- err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
+ sensor_settings[AUTO_EXPOSURE_IDX] = val;
+ err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
- /* The 8 LSBs */
- i2c_data = val & 0xff;
- err = m5602_write_sensor(sd, OV9650_GAIN, &i2c_data, 1);
+ i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
-out:
- return err;
+ return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
}
-int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- 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;
+ *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
+ return 0;
}
-int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set auto white balance to %d", val);
+
+ sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
i2c_data = ((i2c_data & 0xfd) | ((val & 0x01) << 1));
err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
-out:
+
return err;
}
-int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
- *val = (i2c_data & OV9650_AGC_EN) >> 2;
+ *val = sensor_settings[AUTO_GAIN_CTRL_IDX];
PDEBUG(D_V4L2, "Read auto gain control %d", *val);
-
- return err;
+ return 0;
}
-int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set auto gain control to %d", val);
+
+ sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
i2c_data = ((i2c_data & 0xfb) | ((val & 0x01) << 2));
- err = m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
-out:
- return err;
+
+ return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
}
static void ov9650_dump_registers(struct sd *sd)
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h
index f4b33b8e8..c98c40d69 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_ov9650.h
@@ -32,6 +32,7 @@
#define OV9650_BAVE 0x05
#define OV9650_GEAVE 0x06
#define OV9650_RSVD7 0x07
+#define OV9650_COM2 0x09
#define OV9650_PID 0x0a
#define OV9650_VER 0x0b
#define OV9650_COM3 0x0c
@@ -96,6 +97,7 @@
#define OV9650_VGA_SELECT (1 << 6)
#define OV9650_CIF_SELECT (1 << 5)
#define OV9650_QVGA_SELECT (1 << 4)
+#define OV9650_QCIF_SELECT (1 << 3)
#define OV9650_RGB_SELECT (1 << 2)
#define OV9650_RAW_RGB_SELECT (1 << 0)
@@ -115,10 +117,19 @@
#define OV9650_VFLIP (1 << 4)
#define OV9650_HFLIP (1 << 5)
+#define OV9650_SOFT_SLEEP (1 << 4)
+#define OV9650_OUTPUT_DRIVE_2X (1 << 0)
+
+#define OV9650_DENOISE_ENABLE (1 << 5)
+#define OV9650_WHITE_PIXEL_ENABLE (1 << 1)
+#define OV9650_WHITE_PIXEL_OPTION (1 << 0)
+
+#define OV9650_LEFT_OFFSET 0x62
+
#define GAIN_DEFAULT 0x14
#define RED_GAIN_DEFAULT 0x70
#define BLUE_GAIN_DEFAULT 0x20
-#define EXPOSURE_DEFAULT 0x5003
+#define EXPOSURE_DEFAULT 0x1ff
/*****************************************************************************/
@@ -129,173 +140,18 @@ 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_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);
-int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, __s32 val);
-int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
+int ov9650_stop(struct sd *sd);
+void ov9650_disconnect(struct sd *sd);
-static struct m5602_sensor ov9650 = {
+static const 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,
-
- .nctrls = 8,
- .ctrls = {
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0xffff,
- .step = 0x1,
- .default_value = EXPOSURE_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_exposure,
- .get = ov9650_get_exposure
- }, {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0x3ff,
- .step = 0x1,
- .default_value = GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_gain,
- .get = ov9650_get_gain
- }, {
- {
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_red_balance,
- .get = ov9650_get_red_balance
- }, {
- {
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = ov9650_set_blue_balance,
- .get = ov9650_get_blue_balance
- }, {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_hflip,
- .get = ov9650_get_hflip
- }, {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_vflip,
- .get = ov9650_get_vflip
- }, {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_auto_white_balance,
- .get = ov9650_get_auto_white_balance
- }, {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto gain control",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = ov9650_set_auto_gain,
- .get = ov9650_get_auto_gain
- }
- },
-
- .nmodes = 3,
- .modes = {
- {
- 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 =
- 352 * 288,
- .bytesperline = 352,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0
- }, {
- 640,
- 480,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- 640 * 480,
- .bytesperline = 640,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0
- }
- }
+ .stop = ov9650_stop,
+ .disconnect = ov9650_disconnect,
};
static const unsigned char preinit_ov9650[][3] =
@@ -345,6 +201,10 @@ static const unsigned char init_ov9650[][3] =
/* Reset chip */
{SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
+ /* One extra reset is needed in order to make the sensor behave
+ properly when resuming from ram, could be a timing issue */
+ {SENSOR, OV9650_COM7, OV9650_REGISTER_RESET},
+
/* Enable double clock */
{SENSOR, OV9650_CLKRC, 0x80},
/* Do something out of spec with the power */
@@ -352,8 +212,7 @@ static const unsigned char init_ov9650[][3] =
/* Set fast AGC/AEC algorithm with unlimited step size */
{SENSOR, OV9650_COM8, OV9650_FAST_AGC_AEC |
- OV9650_AEC_UNLIM_STEP_SIZE |
- OV9650_AWB_EN | OV9650_AGC_EN},
+ OV9650_AEC_UNLIM_STEP_SIZE},
{SENSOR, OV9650_CHLF, 0x10},
{SENSOR, OV9650_ARBLM, 0xbf},
@@ -424,110 +283,29 @@ static const unsigned char init_ov9650[][3] =
{SENSOR, OV9650_VREF, 0x10},
{SENSOR, OV9650_ADC, 0x04},
{SENSOR, OV9650_HV, 0x40},
- /* Enable denoise, and white-pixel erase */
- {SENSOR, OV9650_COM22, 0x23},
- /* Set the high bits of the exposure value */
- {SENSOR, OV9650_AECH, ((EXPOSURE_DEFAULT & 0xff00) >> 8)},
+ /* Enable denoise, and white-pixel erase */
+ {SENSOR, OV9650_COM22, OV9650_DENOISE_ENABLE |
+ OV9650_WHITE_PIXEL_ENABLE |
+ OV9650_WHITE_PIXEL_OPTION},
/* 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},
-};
-
-static const unsigned char power_down_ov9650[][3] =
-{
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
- {SENSOR, OV9650_COM7, 0x80},
- {SENSOR, OV9650_OFON, 0xf4},
- {SENSOR, OV9650_MVFP, 0x80},
- {SENSOR, OV9650_DBLV, 0x3f},
- {SENSOR, OV9650_RSVD36, 0x49},
- {SENSOR, OV9650_COM7, 0x05},
-
- {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
- {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},
-};
-
-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},
+ /* Put the sensor in soft sleep mode */
+ {SENSOR, OV9650_COM2, OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X},
};
-static const unsigned char QVGA_ov9650[][3] =
+static const unsigned char res_init_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_COM2, OV9650_OUTPUT_DRIVE_2X},
- {SENSOR, OV9650_COM7, OV9650_QVGA_SELECT |
- OV9650_RGB_SELECT |
- OV9650_RAW_RGB_SELECT},
+ {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}
};
#endif
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_po1030.c b/linux/drivers/media/video/gspca/m5602/m5602_po1030.c
index 2e7fb9167..633636365 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_po1030.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_po1030.c
@@ -18,11 +18,194 @@
#include "m5602_po1030.h"
+static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 val);
+static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 *val);
+static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
+ __s32 val);
+static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
+ __s32 *val);
+
+static struct v4l2_pix_format po1030_modes[] = {
+#if 0
+ {
+ 320,
+ 240,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 320 * 240,
+ .bytesperline = 320,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2
+ },
+#endif
+ {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage = 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2
+ }
+};
+
+static const struct ctrl po1030_ctrls[] = {
+#define GAIN_IDX 0
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0x00,
+ .maximum = 0x4f,
+ .step = 0x1,
+ .default_value = PO1030_GLOBAL_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = po1030_set_gain,
+ .get = po1030_get_gain
+ },
+#define EXPOSURE_IDX 1
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x00,
+ .maximum = 0x02ff,
+ .step = 0x1,
+ .default_value = PO1030_EXPOSURE_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = po1030_set_exposure,
+ .get = po1030_get_exposure
+ },
+#define RED_BALANCE_IDX 2
+ {
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = PO1030_RED_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = po1030_set_red_balance,
+ .get = po1030_get_red_balance
+ },
+#define BLUE_BALANCE_IDX 3
+ {
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = PO1030_BLUE_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = po1030_set_blue_balance,
+ .get = po1030_get_blue_balance
+ },
+#define HFLIP_IDX 4
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = po1030_set_hflip,
+ .get = po1030_get_hflip
+ },
+#define VFLIP_IDX 5
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = po1030_set_vflip,
+ .get = po1030_get_vflip
+ },
+#define AUTO_WHITE_BALANCE_IDX 6
+ {
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto white balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = po1030_set_auto_white_balance,
+ .get = po1030_get_auto_white_balance
+ },
+#define AUTO_EXPOSURE_IDX 7
+ {
+ {
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ .set = po1030_set_auto_exposure,
+ .get = po1030_get_auto_exposure
+ },
+#define GREEN_BALANCE_IDX 8
+ {
+ {
+ .id = M5602_V4L2_CID_GREEN_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "green balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = PO1030_GREEN_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = po1030_set_green_balance,
+ .get = po1030_get_green_balance
+ },
+};
+
static void po1030_dump_registers(struct sd *sd);
int po1030_probe(struct sd *sd)
{
- u8 prod_id = 0, ver_id = 0, i;
+ u8 dev_id_h = 0, i;
+ s32 *sensor_settings;
if (force_sensor) {
if (force_sensor == PO1030_SENSOR) {
@@ -46,28 +229,36 @@ int po1030_probe(struct sd *sd)
m5602_write_bridge(sd, preinit_po1030[i][1], data);
}
- if (m5602_read_sensor(sd, 0x3, &prod_id, 1))
+ if (m5602_read_sensor(sd, PO1030_DEVID_H, &dev_id_h, 1))
return -ENODEV;
- if (m5602_read_sensor(sd, 0x4, &ver_id, 1))
- return -ENODEV;
-
- if ((prod_id == 0x02) && (ver_id == 0xef)) {
+ if (dev_id_h == 0x30) {
info("Detected a po1030 sensor");
goto sensor_found;
}
return -ENODEV;
sensor_found:
- sd->gspca_dev.cam.cam_mode = po1030.modes;
- sd->gspca_dev.cam.nmodes = po1030.nmodes;
- sd->desc->ctrls = po1030.ctrls;
- sd->desc->nctrls = po1030.nctrls;
+ sensor_settings = kmalloc(
+ ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL);
+ if (!sensor_settings)
+ return -ENOMEM;
+
+ sd->gspca_dev.cam.cam_mode = po1030_modes;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
+ sd->desc->ctrls = po1030_ctrls;
+ sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls);
+
+ for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++)
+ sensor_settings[i] = po1030_ctrls[i].qctrl.default_value;
+ sd->sensor_priv = sensor_settings;
+
return 0;
}
int po1030_init(struct sd *sd)
{
+ s32 *sensor_settings = sd->sensor_priv;
int i, err = 0;
/* Init the sensor */
@@ -92,218 +283,463 @@ int po1030_init(struct sd *sd)
return -EINVAL;
}
}
+ if (err < 0)
+ return err;
if (dump_sensor)
po1030_dump_registers(sd);
+ err = po1030_set_exposure(&sd->gspca_dev,
+ sensor_settings[EXPOSURE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+ if (err < 0)
+ return err;
+
+ err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+ if (err < 0)
+ return err;
+
+ err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+ if (err < 0)
+ return err;
+
+ err = po1030_set_red_balance(&sd->gspca_dev,
+ sensor_settings[RED_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = po1030_set_blue_balance(&sd->gspca_dev,
+ sensor_settings[BLUE_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = po1030_set_green_balance(&sd->gspca_dev,
+ sensor_settings[GREEN_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = po1030_set_auto_white_balance(&sd->gspca_dev,
+ sensor_settings[AUTO_WHITE_BALANCE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = po1030_set_auto_exposure(&sd->gspca_dev,
+ sensor_settings[AUTO_EXPOSURE_IDX]);
return err;
}
-int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+int po1030_start(struct sd *sd)
{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 i2c_data;
- int err;
+ struct cam *cam = &sd->gspca_dev.cam;
+ int i, err = 0;
+ int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
+ int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
+ int ver_offs = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
+ u8 data;
+
+ switch (width) {
+ case 320:
+ data = PO1030_SUBSAMPLING;
+ err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
+ if (err < 0)
+ return err;
+
+ data = ((width + 3) >> 8) & 0xff;
+ err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
+ if (err < 0)
+ return err;
+
+ data = (width + 3) & 0xff;
+ err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
+ if (err < 0)
+ return err;
+
+ data = ((height + 1) >> 8) & 0xff;
+ err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
+ if (err < 0)
+ return err;
+
+ data = (height + 1) & 0xff;
+ err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
+
+ height += 6;
+ width -= 1;
+ break;
+
+ case 640:
+ data = 0;
+ err = m5602_write_sensor(sd, PO1030_CONTROL3, &data, 1);
+ if (err < 0)
+ return err;
+
+ data = ((width + 7) >> 8) & 0xff;
+ err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_H, &data, 1);
+ if (err < 0)
+ return err;
+
+ data = (width + 7) & 0xff;
+ err = m5602_write_sensor(sd, PO1030_WINDOWWIDTH_L, &data, 1);
+ if (err < 0)
+ return err;
+
+ data = ((height + 3) >> 8) & 0xff;
+ err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_H, &data, 1);
+ if (err < 0)
+ return err;
+
+ data = (height + 3) & 0xff;
+ err = m5602_write_sensor(sd, PO1030_WINDOWHEIGHT_L, &data, 1);
+
+ height += 12;
+ width -= 2;
+ break;
+ }
+ err = m5602_write_bridge(sd, M5602_XB_SENSOR_TYPE, 0x0c);
+ if (err < 0)
+ return err;
- err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_H,
- &i2c_data, 1);
+ err = m5602_write_bridge(sd, M5602_XB_LINE_OF_FRAME_H, 0x81);
if (err < 0)
- goto out;
- *val = (i2c_data << 8);
+ return err;
- err = m5602_read_sensor(sd, PO1030_REG_INTEGLINES_M,
- &i2c_data, 1);
- *val |= i2c_data;
+ err = m5602_write_bridge(sd, M5602_XB_PIX_OF_LINE_H, 0x82);
+ if (err < 0)
+ return err;
- PDEBUG(D_V4L2, "Exposure read as %d", *val);
-out:
+ err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0x01);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA,
+ ((ver_offs >> 8) & 0xff));
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (ver_offs & 0xff));
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < 2 && !err; i++)
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff));
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < 2 && !err; i++)
+ err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0);
+
+ for (i = 0; i < 2 && !err; i++)
+ err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
+
+ for (i = 0; i < 2 && !err; i++)
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width >> 8) & 0xff);
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, (width & 0xff));
+ if (err < 0)
+ return err;
+
+ err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0);
return err;
}
-int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[EXPOSURE_IDX];
+ PDEBUG(D_V4L2, "Exposure read as %d", *val);
+ return 0;
+}
+
+static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
+ sensor_settings[EXPOSURE_IDX] = val;
PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
i2c_data = ((val & 0xff00) >> 8);
PDEBUG(D_V4L2, "Set exposure to high byte to 0x%x",
i2c_data);
- err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_H,
+ err = m5602_write_sensor(sd, PO1030_INTEGLINES_H,
&i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
i2c_data = (val & 0xff);
PDEBUG(D_V4L2, "Set exposure to low byte to 0x%x",
i2c_data);
- err = m5602_write_sensor(sd, PO1030_REG_INTEGLINES_M,
+ err = m5602_write_sensor(sd, PO1030_INTEGLINES_M,
&i2c_data, 1);
-out:
return err;
}
-int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 i2c_data;
- int err;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN,
- &i2c_data, 1);
- *val = i2c_data;
+ *val = sensor_settings[GAIN_IDX];
PDEBUG(D_V4L2, "Read global gain %d", *val);
-
- return err;
+ return 0;
}
-int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- err = m5602_read_sensor(sd, PO1030_REG_CONTROL2,
+ sensor_settings[GAIN_IDX] = val;
+
+ i2c_data = val & 0xff;
+ PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
+ err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,
&i2c_data, 1);
+ return err;
+}
- *val = (i2c_data >> 7) & 0x01 ;
+static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+ *val = sensor_settings[HFLIP_IDX];
PDEBUG(D_V4L2, "Read hflip %d", *val);
- return err;
+ return 0;
}
-int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
+ sensor_settings[HFLIP_IDX] = val;
+
PDEBUG(D_V4L2, "Set hflip %d", val);
- err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
+ err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7);
- err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
+ err = m5602_write_sensor(sd, PO1030_CONTROL2,
&i2c_data, 1);
-out:
return err;
}
-int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 i2c_data;
- int err;
-
- err = m5602_read_sensor(sd, PO1030_REG_GLOBALGAIN,
- &i2c_data, 1);
-
- *val = (i2c_data >> 6) & 0x01;
+ s32 *sensor_settings = sd->sensor_priv;
+ *val = sensor_settings[VFLIP_IDX];
PDEBUG(D_V4L2, "Read vflip %d", *val);
- return err;
+ return 0;
}
-int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
+ sensor_settings[VFLIP_IDX] = val;
+
PDEBUG(D_V4L2, "Set vflip %d", val);
- err = m5602_read_sensor(sd, PO1030_REG_CONTROL2, &i2c_data, 1);
+ err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
if (err < 0)
- goto out;
+ return err;
i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
- err = m5602_write_sensor(sd, PO1030_REG_CONTROL2,
+ err = m5602_write_sensor(sd, PO1030_CONTROL2,
&i2c_data, 1);
-out:
return err;
}
-int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_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];
+ PDEBUG(D_V4L2, "Read red gain %d", *val);
+ return 0;
+}
+
+static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
+ sensor_settings[RED_BALANCE_IDX] = val;
+
i2c_data = val & 0xff;
- PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
- err = m5602_write_sensor(sd, PO1030_REG_GLOBALGAIN,
+ PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
+ err = m5602_write_sensor(sd, PO1030_RED_GAIN,
&i2c_data, 1);
return err;
}
-int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 i2c_data;
- int err;
+ s32 *sensor_settings = sd->sensor_priv;
- 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;
+ *val = sensor_settings[BLUE_BALANCE_IDX];
+ PDEBUG(D_V4L2, "Read blue gain %d", *val);
+
+ return 0;
}
-int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
+ sensor_settings[BLUE_BALANCE_IDX] = val;
+
i2c_data = val & 0xff;
- PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
- err = m5602_write_sensor(sd, PO1030_REG_RED_GAIN,
+ PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
+ err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
&i2c_data, 1);
+
return err;
}
-int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[GREEN_BALANCE_IDX];
+ PDEBUG(D_V4L2, "Read green gain %d", *val);
+
+ return 0;
+}
+
+static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- err = m5602_read_sensor(sd, PO1030_REG_BLUE_GAIN,
+ sensor_settings[GREEN_BALANCE_IDX] = val;
+ i2c_data = val & 0xff;
+ PDEBUG(D_V4L2, "Set green gain to %d", i2c_data);
+
+ err = m5602_write_sensor(sd, PO1030_GREEN_1_GAIN,
+ &i2c_data, 1);
+ if (err < 0)
+ return err;
+
+ return m5602_write_sensor(sd, PO1030_GREEN_2_GAIN,
&i2c_data, 1);
- *val = i2c_data;
- PDEBUG(D_V4L2, "Read blue gain %d", *val);
+}
- return err;
+static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
+ PDEBUG(D_V4L2, "Auto white balancing is %d", *val);
+
+ return 0;
}
-int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
+ __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
- i2c_data = val & 0xff;
- PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
- err = m5602_write_sensor(sd, PO1030_REG_BLUE_GAIN,
- &i2c_data, 1);
+ sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
+
+ err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
+ if (err < 0)
+ return err;
+
+ PDEBUG(D_V4L2, "Set auto white balance to %d", val);
+ i2c_data = (i2c_data & 0xfe) | (val & 0x01);
+ err = m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
return err;
}
-int po1030_power_down(struct sd *sd)
+static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
+ __s32 *val)
{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[AUTO_EXPOSURE_IDX];
+ PDEBUG(D_V4L2, "Auto exposure is %d", *val);
return 0;
}
+static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
+ __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+ u8 i2c_data;
+ int err;
+
+ sensor_settings[AUTO_EXPOSURE_IDX] = val;
+ err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
+ if (err < 0)
+ return err;
+
+ PDEBUG(D_V4L2, "Set auto exposure to %d", val);
+ i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
+ return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
+}
+
+void po1030_disconnect(struct sd *sd)
+{
+ sd->sensor = NULL;
+ kfree(sd->sensor_priv);
+}
+
static void po1030_dump_registers(struct sd *sd)
{
int address;
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_po1030.h b/linux/drivers/media/video/gspca/m5602/m5602_po1030.h
index def39d5bc..1ea380b2b 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_po1030.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_po1030.h
@@ -25,98 +25,123 @@
/*****************************************************************************/
-#define PO1030_REG_DEVID_H 0x00
-#define PO1030_REG_DEVID_L 0x01
-#define PO1030_REG_FRAMEWIDTH_H 0x04
-#define PO1030_REG_FRAMEWIDTH_L 0x05
-#define PO1030_REG_FRAMEHEIGHT_H 0x06
-#define PO1030_REG_FRAMEHEIGHT_L 0x07
-#define PO1030_REG_WINDOWX_H 0x08
-#define PO1030_REG_WINDOWX_L 0x09
-#define PO1030_REG_WINDOWY_H 0x0a
-#define PO1030_REG_WINDOWY_L 0x0b
-#define PO1030_REG_WINDOWWIDTH_H 0x0c
-#define PO1030_REG_WINDOWWIDTH_L 0x0d
-#define PO1030_REG_WINDOWHEIGHT_H 0x0e
-#define PO1030_REG_WINDOWHEIGHT_L 0x0f
-
-#define PO1030_REG_GLOBALIBIAS 0x12
-#define PO1030_REG_PIXELIBIAS 0x13
-
-#define PO1030_REG_GLOBALGAIN 0x15
-#define PO1030_REG_RED_GAIN 0x16
-#define PO1030_REG_GREEN_1_GAIN 0x17
-#define PO1030_REG_BLUE_GAIN 0x18
-#define PO1030_REG_GREEN_2_GAIN 0x19
-
-#define PO1030_REG_INTEGLINES_H 0x1a
-#define PO1030_REG_INTEGLINES_M 0x1b
-#define PO1030_REG_INTEGLINES_L 0x1c
-
-#define PO1030_REG_CONTROL1 0x1d
-#define PO1030_REG_CONTROL2 0x1e
-#define PO1030_REG_CONTROL3 0x1f
-#define PO1030_REG_CONTROL4 0x20
-
-#define PO1030_REG_PERIOD50_H 0x23
-#define PO1030_REG_PERIOD50_L 0x24
-#define PO1030_REG_PERIOD60_H 0x25
-#define PO1030_REG_PERIOD60_L 0x26
-#define PO1030_REG_REGCLK167 0x27
-#define PO1030_REG_DELTA50 0x28
-#define PO1030_REG_DELTA60 0x29
-
-#define PO1030_REG_ADCOFFSET 0x2c
+#define PO1030_DEVID_H 0x00
+#define PO1030_DEVID_L 0x01
+#define PO1030_FRAMEWIDTH_H 0x04
+#define PO1030_FRAMEWIDTH_L 0x05
+#define PO1030_FRAMEHEIGHT_H 0x06
+#define PO1030_FRAMEHEIGHT_L 0x07
+#define PO1030_WINDOWX_H 0x08
+#define PO1030_WINDOWX_L 0x09
+#define PO1030_WINDOWY_H 0x0a
+#define PO1030_WINDOWY_L 0x0b
+#define PO1030_WINDOWWIDTH_H 0x0c
+#define PO1030_WINDOWWIDTH_L 0x0d
+#define PO1030_WINDOWHEIGHT_H 0x0e
+#define PO1030_WINDOWHEIGHT_L 0x0f
+
+#define PO1030_GLOBALIBIAS 0x12
+#define PO1030_PIXELIBIAS 0x13
+
+#define PO1030_GLOBALGAIN 0x15
+#define PO1030_RED_GAIN 0x16
+#define PO1030_GREEN_1_GAIN 0x17
+#define PO1030_BLUE_GAIN 0x18
+#define PO1030_GREEN_2_GAIN 0x19
+
+#define PO1030_INTEGLINES_H 0x1a
+#define PO1030_INTEGLINES_M 0x1b
+#define PO1030_INTEGLINES_L 0x1c
+
+#define PO1030_CONTROL1 0x1d
+#define PO1030_CONTROL2 0x1e
+#define PO1030_CONTROL3 0x1f
+#define PO1030_CONTROL4 0x20
+
+#define PO1030_PERIOD50_H 0x23
+#define PO1030_PERIOD50_L 0x24
+#define PO1030_PERIOD60_H 0x25
+#define PO1030_PERIOD60_L 0x26
+#define PO1030_REGCLK167 0x27
+#define PO1030_FLICKER_DELTA50 0x28
+#define PO1030_FLICKERDELTA60 0x29
+
+#define PO1030_ADCOFFSET 0x2c
/* Gamma Correction Coeffs */
-#define PO1030_REG_GC0 0x2d
-#define PO1030_REG_GC1 0x2e
-#define PO1030_REG_GC2 0x2f
-#define PO1030_REG_GC3 0x30
-#define PO1030_REG_GC4 0x31
-#define PO1030_REG_GC5 0x32
-#define PO1030_REG_GC6 0x33
-#define PO1030_REG_GC7 0x34
+#define PO1030_GC0 0x2d
+#define PO1030_GC1 0x2e
+#define PO1030_GC2 0x2f
+#define PO1030_GC3 0x30
+#define PO1030_GC4 0x31
+#define PO1030_GC5 0x32
+#define PO1030_GC6 0x33
+#define PO1030_GC7 0x34
/* Color Transform Matrix */
-#define PO1030_REG_CT0 0x35
-#define PO1030_REG_CT1 0x36
-#define PO1030_REG_CT2 0x37
-#define PO1030_REG_CT3 0x38
-#define PO1030_REG_CT4 0x39
-#define PO1030_REG_CT5 0x3a
-#define PO1030_REG_CT6 0x3b
-#define PO1030_REG_CT7 0x3c
-#define PO1030_REG_CT8 0x3d
-
-#define PO1030_REG_AUTOCTRL1 0x3e
-#define PO1030_REG_AUTOCTRL2 0x3f
-
-#define PO1030_REG_YTARGET 0x40
-#define PO1030_REG_GLOBALGAINMIN 0x41
-#define PO1030_REG_GLOBALGAINMAX 0x42
+#define PO1030_CT0 0x35
+#define PO1030_CT1 0x36
+#define PO1030_CT2 0x37
+#define PO1030_CT3 0x38
+#define PO1030_CT4 0x39
+#define PO1030_CT5 0x3a
+#define PO1030_CT6 0x3b
+#define PO1030_CT7 0x3c
+#define PO1030_CT8 0x3d
+
+#define PO1030_AUTOCTRL1 0x3e
+#define PO1030_AUTOCTRL2 0x3f
+
+#define PO1030_YTARGET 0x40
+#define PO1030_GLOBALGAINMIN 0x41
+#define PO1030_GLOBALGAINMAX 0x42
+
+#define PO1030_AWB_RED_TUNING 0x47
+#define PO1030_AWB_BLUE_TUNING 0x48
/* Output format control */
-#define PO1030_REG_OUTFORMCTRL1 0x5a
-#define PO1030_REG_OUTFORMCTRL2 0x5b
-#define PO1030_REG_OUTFORMCTRL3 0x5c
-#define PO1030_REG_OUTFORMCTRL4 0x5d
-#define PO1030_REG_OUTFORMCTRL5 0x5e
+#define PO1030_OUTFORMCTRL1 0x5a
+#define PO1030_OUTFORMCTRL2 0x5b
+#define PO1030_OUTFORMCTRL3 0x5c
+#define PO1030_OUTFORMCTRL4 0x5d
+#define PO1030_OUTFORMCTRL5 0x5e
-/* Imaging coefficients */
-#define PO1030_REG_YBRIGHT 0x73
-#define PO1030_REG_YCONTRAST 0x74
-#define PO1030_REG_YSATURATION 0x75
+#define PO1030_EDGE_ENH_OFF 0x5f
+#define PO1030_EGA 0x60
-#define PO1030_HFLIP (1 << 7)
-#define PO1030_VFLIP (1 << 6)
+#define PO1030_Cb_U_GAIN 0x63
+#define PO1030_Cr_V_GAIN 0x64
+
+#define PO1030_YCONTRAST 0x74
+#define PO1030_YSATURATION 0x75
+
+#define PO1030_HFLIP (1 << 7)
+#define PO1030_VFLIP (1 << 6)
+
+#define PO1030_HREF_ENABLE (1 << 6)
+
+#define PO1030_RAW_RGB_BAYER 0x4
+
+#define PO1030_FRAME_EQUAL (1 << 3)
+#define PO1030_AUTO_SUBSAMPLING (1 << 4)
+
+#define PO1030_WEIGHT_WIN_2X (1 << 3)
+
+#define PO1030_SHUTTER_MODE (1 << 6)
+#define PO1030_AUTO_SUBSAMPLING (1 << 4)
+#define PO1030_FRAME_EQUAL (1 << 3)
+
+#define PO1030_SENSOR_RESET (1 << 5)
+
+#define PO1030_SUBSAMPLING (1 << 6)
/*****************************************************************************/
#define PO1030_GLOBAL_GAIN_DEFAULT 0x12
#define PO1030_EXPOSURE_DEFAULT 0x0085
-#define PO1030_BLUE_GAIN_DEFAULT 0x40
-#define PO1030_RED_GAIN_DEFAULT 0x40
+#define PO1030_BLUE_GAIN_DEFAULT 0x36
+#define PO1030_RED_GAIN_DEFAULT 0x36
+#define PO1030_GREEN_GAIN_DEFAULT 0x40
/*****************************************************************************/
@@ -126,22 +151,10 @@ extern int dump_sensor;
int po1030_probe(struct sd *sd);
int po1030_init(struct sd *sd);
-int po1030_power_down(struct sd *sd);
-
-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);
-int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-
-static struct m5602_sensor po1030 = {
+int po1030_start(struct sd *sd);
+void po1030_disconnect(struct sd *sd);
+
+static const struct m5602_sensor po1030 = {
.name = "PO1030",
.i2c_slave_id = 0xdc,
@@ -149,103 +162,8 @@ static struct m5602_sensor po1030 = {
.probe = po1030_probe,
.init = po1030_init,
- .power_down = po1030_power_down,
-
- .nctrls = 6,
- .ctrls = {
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0x4f,
- .step = 0x1,
- .default_value = PO1030_GLOBAL_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_gain,
- .get = po1030_get_gain
- }, {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0x02ff,
- .step = 0x1,
- .default_value = PO1030_EXPOSURE_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_exposure,
- .get = po1030_get_exposure
- }, {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_red_balance,
- .get = po1030_get_red_balance
- }, {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = po1030_set_blue_balance,
- .get = po1030_get_blue_balance
- }, {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_hflip,
- .get = po1030_get_hflip
- }, {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- },
- .set = po1030_set_vflip,
- .get = po1030_get_vflip
- }
- },
-
- .nmodes = 1,
- .modes = {
- {
- M5602_DEFAULT_FRAME_WIDTH,
- M5602_DEFAULT_FRAME_HEIGHT,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
- .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1
- }
- }
+ .start = po1030_start,
+ .disconnect = po1030_disconnect,
};
static const unsigned char preinit_po1030[][3] =
@@ -255,248 +173,103 @@ static const unsigned char preinit_po1030[][3] =
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
-
- {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
-
- {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
- {BRIDGE, M5602_XB_GPIO_DIR_H, 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_DIV, 0x06},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
- {BRIDGE, M5602_XB_SIG_INI, 0x01},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x02},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x87},
- {BRIDGE, M5602_XB_SIG_INI, 0x00},
-
- {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
-
{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
+
+ {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
+
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
{BRIDGE, M5602_XB_GPIO_DAT, 0x00}
};
-static const unsigned char init_po1030[][4] =
+static const unsigned char init_po1030[][3] =
{
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
- /*sequence 1*/
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d},
-
{BRIDGE, M5602_XB_SENSOR_CTRL, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
{BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
- /*end of sequence 1*/
- /*sequence 2 (same as stop sequence)*/
- {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
- {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x04},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
- {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
- {BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
-
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
- /*end of sequence 2*/
-
- /*sequence 5*/
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
- {BRIDGE, M5602_XB_SIG_INI, 0x01},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x02},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x87},
- {BRIDGE, M5602_XB_SIG_INI, 0x00},
- /*end of sequence 5*/
-
- /*sequence 2 stop */
- {SENSOR, PO1030_REG_AUTOCTRL2, 0x24},
+ {SENSOR, PO1030_AUTOCTRL2, PO1030_SENSOR_RESET | (1 << 2)},
{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
{BRIDGE, M5602_XB_GPIO_DAT, 0x04},
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06},
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x02},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x04},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
- /*end of sequence 2 stop */
-
-/* ---------------------------------
- * end of init - begin of start
- * --------------------------------- */
-
- /*sequence 3*/
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
- /*end of sequence 3*/
- /*sequence 4*/
{BRIDGE, M5602_XB_GPIO_DIR, 0x05},
{BRIDGE, M5602_XB_GPIO_DAT, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
- {SENSOR, PO1030_REG_AUTOCTRL2, 0x04},
+ {SENSOR, PO1030_AUTOCTRL2, 0x04},
+
+ {SENSOR, PO1030_OUTFORMCTRL2, PO1030_RAW_RGB_BAYER},
+ {SENSOR, PO1030_AUTOCTRL1, PO1030_WEIGHT_WIN_2X},
+
+ {SENSOR, PO1030_CONTROL2, 0x03},
+ {SENSOR, 0x21, 0x90},
+ {SENSOR, PO1030_YTARGET, 0x60},
+ {SENSOR, 0x59, 0x13},
+ {SENSOR, PO1030_OUTFORMCTRL1, PO1030_HREF_ENABLE},
+ {SENSOR, PO1030_EDGE_ENH_OFF, 0x00},
+ {SENSOR, PO1030_EGA, 0x80},
+ {SENSOR, 0x78, 0x14},
+ {SENSOR, 0x6f, 0x01},
+ {SENSOR, PO1030_GLOBALGAINMAX, 0x14},
+ {SENSOR, PO1030_Cb_U_GAIN, 0x38},
+ {SENSOR, PO1030_Cr_V_GAIN, 0x38},
+ {SENSOR, PO1030_CONTROL1, PO1030_SHUTTER_MODE |
+ PO1030_AUTO_SUBSAMPLING |
+ PO1030_FRAME_EQUAL},
+ {SENSOR, PO1030_GC0, 0x10},
+ {SENSOR, PO1030_GC1, 0x20},
+ {SENSOR, PO1030_GC2, 0x40},
+ {SENSOR, PO1030_GC3, 0x60},
+ {SENSOR, PO1030_GC4, 0x80},
+ {SENSOR, PO1030_GC5, 0xa0},
+ {SENSOR, PO1030_GC6, 0xc0},
+ {SENSOR, PO1030_GC7, 0xff},
/* Set the width to 751 */
- {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02},
- {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef},
+ {SENSOR, PO1030_FRAMEWIDTH_H, 0x02},
+ {SENSOR, PO1030_FRAMEWIDTH_L, 0xef},
/* Set the height to 540 */
- {SENSOR, PO1030_REG_FRAMEHEIGHT_H, 0x02},
- {SENSOR, PO1030_REG_FRAMEHEIGHT_L, 0x1c},
+ {SENSOR, PO1030_FRAMEHEIGHT_H, 0x02},
+ {SENSOR, PO1030_FRAMEHEIGHT_L, 0x1c},
/* Set the x window to 1 */
- {SENSOR, PO1030_REG_WINDOWX_H, 0x00},
- {SENSOR, PO1030_REG_WINDOWX_L, 0x01},
+ {SENSOR, PO1030_WINDOWX_H, 0x00},
+ {SENSOR, PO1030_WINDOWX_L, 0x01},
/* Set the y window to 1 */
- {SENSOR, PO1030_REG_WINDOWY_H, 0x00},
- {SENSOR, PO1030_REG_WINDOWY_L, 0x01},
-
- {SENSOR, PO1030_REG_WINDOWWIDTH_H, 0x02},
- {SENSOR, PO1030_REG_WINDOWWIDTH_L, 0x87},
- {SENSOR, PO1030_REG_WINDOWHEIGHT_H, 0x01},
- {SENSOR, PO1030_REG_WINDOWHEIGHT_L, 0xe3},
-
- {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04},
- {SENSOR, PO1030_REG_OUTFORMCTRL2, 0x04},
- {SENSOR, PO1030_REG_AUTOCTRL1, 0x08},
- {SENSOR, PO1030_REG_CONTROL2, 0x03},
- {SENSOR, 0x21, 0x90},
- {SENSOR, PO1030_REG_YTARGET, 0x60},
- {SENSOR, 0x59, 0x13},
- {SENSOR, PO1030_REG_OUTFORMCTRL1, 0x40},
- {SENSOR, 0x5f, 0x00},
- {SENSOR, 0x60, 0x80},
- {SENSOR, 0x78, 0x14},
- {SENSOR, 0x6f, 0x01},
- {SENSOR, PO1030_REG_CONTROL1, 0x18},
- {SENSOR, PO1030_REG_GLOBALGAINMAX, 0x14},
- {SENSOR, 0x63, 0x38},
- {SENSOR, 0x64, 0x38},
- {SENSOR, PO1030_REG_CONTROL1, 0x58},
- {SENSOR, PO1030_REG_RED_GAIN, 0x30},
- {SENSOR, PO1030_REG_GREEN_1_GAIN, 0x30},
- {SENSOR, PO1030_REG_BLUE_GAIN, 0x30},
- {SENSOR, PO1030_REG_GREEN_2_GAIN, 0x30},
- {SENSOR, PO1030_REG_GC0, 0x10},
- {SENSOR, PO1030_REG_GC1, 0x20},
- {SENSOR, PO1030_REG_GC2, 0x40},
- {SENSOR, PO1030_REG_GC3, 0x60},
- {SENSOR, PO1030_REG_GC4, 0x80},
- {SENSOR, PO1030_REG_GC5, 0xa0},
- {SENSOR, PO1030_REG_GC6, 0xc0},
- {SENSOR, PO1030_REG_GC7, 0xff},
- /*end of sequence 4*/
- /*sequence 5*/
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0c},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82},
- {BRIDGE, M5602_XB_SIG_INI, 0x01},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x02},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x01},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xec},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x00},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x02},
- {BRIDGE, M5602_XB_HSYNC_PARA, 0x7e},
- {BRIDGE, M5602_XB_SIG_INI, 0x00},
- /*end of sequence 5*/
-
- /*sequence 6*/
- /* Changing 40 in f0 the image becomes green in bayer mode and red in
- * rgb mode */
- {SENSOR, PO1030_REG_RED_GAIN, PO1030_RED_GAIN_DEFAULT},
- /* in changing 40 in f0 the image becomes green in bayer mode and red in
- * rgb mode */
- {SENSOR, PO1030_REG_BLUE_GAIN, PO1030_BLUE_GAIN_DEFAULT},
+ {SENSOR, PO1030_WINDOWY_H, 0x00},
+ {SENSOR, PO1030_WINDOWY_L, 0x01},
/* with a very low lighted environment increase the exposure but
* decrease the FPS (Frame Per Second) */
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
- /* Controls high exposure more than SENSOR_LOW_EXPOSURE, use only in
- * low lighted environment (f0 is more than ff ?)*/
- {SENSOR, PO1030_REG_INTEGLINES_H, ((PO1030_EXPOSURE_DEFAULT >> 2)
- & 0xff)},
-
- /* Controls middle exposure, use only in high lighted environment */
- {SENSOR, PO1030_REG_INTEGLINES_M, PO1030_EXPOSURE_DEFAULT & 0xff},
-
- /* Controls clarity (not sure) */
- {SENSOR, PO1030_REG_INTEGLINES_L, 0x00},
- /* Controls gain (the image is more lighted) */
- {SENSOR, PO1030_REG_GLOBALGAIN, PO1030_GLOBAL_GAIN_DEFAULT},
-
- /* Sets the width */
- {SENSOR, PO1030_REG_FRAMEWIDTH_H, 0x02},
- {SENSOR, PO1030_REG_FRAMEWIDTH_L, 0xef}
- /*end of sequence 6*/
+ {BRIDGE, M5602_XB_GPIO_DIR, 0x05},
+ {BRIDGE, M5602_XB_GPIO_DAT, 0x00},
+ {BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
+ {BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
};
#endif
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index 7e79f7eca..81f24d413 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -18,6 +18,19 @@
#include "m5602_s5k4aa.h"
+static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+
static
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 24)
const
@@ -48,10 +61,131 @@ static
DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
DMI_MATCH(DMI_PRODUCT_NAME, "GX700/GX705/EX700")
}
+ }, {
+ .ident = "MSI L735",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star International"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MS-1717X")
+ }
},
{ }
};
+static struct v4l2_pix_format s5k4aa_modes[] = {
+ {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ },
+ {
+ 1280,
+ 1024,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 1280 * 1024,
+ .bytesperline = 1280,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ }
+};
+
+static const struct ctrl s5k4aa_ctrls[] = {
+#define VFLIP_IDX 0
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = s5k4aa_set_vflip,
+ .get = s5k4aa_get_vflip
+ },
+#define HFLIP_IDX 1
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = s5k4aa_set_hflip,
+ .get = s5k4aa_get_hflip
+ },
+#define GAIN_IDX 2
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = S5K4AA_DEFAULT_GAIN,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = s5k4aa_set_gain,
+ .get = s5k4aa_get_gain
+ },
+#define EXPOSURE_IDX 3
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 13,
+ .maximum = 0xfff,
+ .step = 1,
+ .default_value = 0x100,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = s5k4aa_set_exposure,
+ .get = s5k4aa_get_exposure
+ },
+#define NOISE_SUPP_IDX 4
+ {
+ {
+ .id = V4L2_CID_PRIVATE_BASE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Noise suppression (smoothing)",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ .set = s5k4aa_set_noise,
+ .get = s5k4aa_get_noise
+ },
+#define BRIGHTNESS_IDX 5
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0x1f,
+ .step = 1,
+ .default_value = S5K4AA_DEFAULT_BRIGHTNESS,
+ },
+ .set = s5k4aa_set_brightness,
+ .get = s5k4aa_get_brightness
+ },
+
+};
+
static void s5k4aa_dump_registers(struct sd *sd);
int s5k4aa_probe(struct sd *sd)
@@ -59,6 +193,7 @@ int s5k4aa_probe(struct sd *sd)
u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
int i, err = 0;
+ s32 *sensor_settings;
if (force_sensor) {
if (force_sensor == S5K4AA_SENSOR) {
@@ -117,14 +252,131 @@ int s5k4aa_probe(struct sd *sd)
info("Detected a s5k4aa sensor");
sensor_found:
- sd->gspca_dev.cam.cam_mode = s5k4aa.modes;
- sd->gspca_dev.cam.nmodes = s5k4aa.nmodes;
- sd->desc->ctrls = s5k4aa.ctrls;
- sd->desc->nctrls = s5k4aa.nctrls;
+ sensor_settings = kmalloc(
+ ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
+ if (!sensor_settings)
+ return -ENOMEM;
+
+ sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
+ sd->desc->ctrls = s5k4aa_ctrls;
+ sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
+
+ for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
+ sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
+ sd->sensor_priv = sensor_settings;
return 0;
}
+int s5k4aa_start(struct sd *sd)
+{
+ int i, err = 0;
+ u8 data[2];
+ struct cam *cam = &sd->gspca_dev.cam;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
+ case 1280:
+ PDEBUG(D_V4L2, "Configuring camera for SXGA mode");
+
+ for (i = 0; i < ARRAY_SIZE(SXGA_s5k4aa); i++) {
+ switch (SXGA_s5k4aa[i][0]) {
+ case BRIDGE:
+ err = m5602_write_bridge(sd,
+ SXGA_s5k4aa[i][1],
+ SXGA_s5k4aa[i][2]);
+ break;
+
+ case SENSOR:
+ data[0] = SXGA_s5k4aa[i][2];
+ err = m5602_write_sensor(sd,
+ SXGA_s5k4aa[i][1],
+ data, 1);
+ break;
+
+ case SENSOR_LONG:
+ data[0] = SXGA_s5k4aa[i][2];
+ data[1] = SXGA_s5k4aa[i][3];
+ err = m5602_write_sensor(sd,
+ SXGA_s5k4aa[i][1],
+ data, 2);
+ break;
+
+ default:
+ err("Invalid stream command, exiting init");
+ return -EINVAL;
+ }
+ }
+ err = s5k4aa_set_noise(&sd->gspca_dev, 0);
+ if (err < 0)
+ return err;
+ break;
+
+ case 640:
+ PDEBUG(D_V4L2, "Configuring camera for VGA mode");
+
+ for (i = 0; i < ARRAY_SIZE(VGA_s5k4aa); i++) {
+ switch (VGA_s5k4aa[i][0]) {
+ case BRIDGE:
+ err = m5602_write_bridge(sd,
+ VGA_s5k4aa[i][1],
+ VGA_s5k4aa[i][2]);
+ break;
+
+ case SENSOR:
+ data[0] = VGA_s5k4aa[i][2];
+ err = m5602_write_sensor(sd,
+ VGA_s5k4aa[i][1],
+ data, 1);
+ break;
+
+ case SENSOR_LONG:
+ data[0] = VGA_s5k4aa[i][2];
+ data[1] = VGA_s5k4aa[i][3];
+ err = m5602_write_sensor(sd,
+ VGA_s5k4aa[i][1],
+ data, 2);
+ break;
+
+ default:
+ err("Invalid stream command, exiting init");
+ return -EINVAL;
+ }
+ }
+ err = s5k4aa_set_noise(&sd->gspca_dev, 1);
+ if (err < 0)
+ return err;
+ break;
+ }
+ if (err < 0)
+ return err;
+
+ err = s5k4aa_set_exposure(&sd->gspca_dev,
+ sensor_settings[EXPOSURE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+ if (err < 0)
+ return err;
+
+ err = s5k4aa_set_brightness(&sd->gspca_dev,
+ sensor_settings[BRIGHTNESS_IDX]);
+ if (err < 0)
+ return err;
+
+ err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
+ if (err < 0)
+ return err;
+
+ err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+ if (err < 0)
+ return err;
+
+ return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+}
+
int s5k4aa_init(struct sd *sd)
{
int i, err = 0;
@@ -160,222 +412,228 @@ int s5k4aa_init(struct sd *sd)
if (dump_sensor)
s5k4aa_dump_registers(sd);
- if (!err && dmi_check_system(s5k4aa_vflip_dmi_table)) {
- u8 data = 0x02;
- info("vertical flip quirk active");
- 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;
- m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
-
- /* Decrement COLSTART to preserve color order (BGGR) */
- m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
- data--;
- m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
-
- /* Increment ROWSTART to preserve color order (BGGR) */
- m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
- data++;
- m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
- }
-
- return (err < 0) ? err : 0;
-}
-
-int s5k4aa_power_down(struct sd *sd)
-{
- return 0;
+ return err;
}
-int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 data = S5K4AA_PAGE_MAP_2;
- int err;
-
- err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
- if (err < 0)
- goto out;
-
- err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
- if (err < 0)
- goto out;
+ s32 *sensor_settings = sd->sensor_priv;
- *val = data << 8;
- err = m5602_read_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
- *val |= data;
+ *val = sensor_settings[EXPOSURE_IDX];
PDEBUG(D_V4L2, "Read exposure %d", *val);
-out:
- return err;
+
+ return 0;
}
-int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
+ sensor_settings[EXPOSURE_IDX] = val;
PDEBUG(D_V4L2, "Set exposure to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
data = (val >> 8) & 0xff;
err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_HI, &data, 1);
if (err < 0)
- goto out;
+ return err;
data = val & 0xff;
err = m5602_write_sensor(sd, S5K4AA_EXPOSURE_LO, &data, 1);
-out:
+
return err;
}
-int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 data = S5K4AA_PAGE_MAP_2;
- int err;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
- if (err < 0)
- goto out;
-
- err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
- *val = (data & S5K4AA_RM_V_FLIP) >> 7;
+ *val = sensor_settings[VFLIP_IDX];
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
-out:
- return err;
+ return 0;
}
-int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
+ sensor_settings[VFLIP_IDX] = val;
+
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
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 = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+ return err;
+
+ err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
- goto out;
+ return err;
- if (val) {
- err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
- if (err < 0)
- goto out;
+ if (dmi_check_system(s5k4aa_vflip_dmi_table))
+ val = !val;
- data++;
- err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
- } else {
- err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
- if (err < 0)
- goto out;
+ data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
+ err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+ if (err < 0)
+ return err;
- data--;
- err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
- }
-out:
+ err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
+ if (err < 0)
+ return err;
+ data = (data & 0xfe) | !val;
+ err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
return err;
}
-int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 data = S5K4AA_PAGE_MAP_2;
- int err;
-
- err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
- if (err < 0)
- goto out;
+ s32 *sensor_settings = sd->sensor_priv;
- err = m5602_read_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
- *val = (data & S5K4AA_RM_H_FLIP) >> 6;
+ *val = sensor_settings[HFLIP_IDX];
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
-out:
- return err;
+
+ return 0;
}
-int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- PDEBUG(D_V4L2, "Set horizontal flip to %d",
- val);
+ sensor_settings[HFLIP_IDX] = val;
+
+ PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
- goto out;
+ return err;
+
+ err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
+ if (err < 0)
+ return err;
+
+ if (dmi_check_system(s5k4aa_vflip_dmi_table))
+ val = !val;
data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
- goto out;
+ return err;
- if (val) {
- err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
- if (err < 0)
- goto out;
- data++;
- err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
- if (err < 0)
- goto out;
- } else {
- err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
- if (err < 0)
- goto out;
- data--;
- err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
- }
-out:
+ err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
+ if (err < 0)
+ return err;
+ data = (data & 0xfe) | !val;
+ err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
return err;
}
-int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k4aa_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];
+ PDEBUG(D_V4L2, "Read gain %d", *val);
+ return 0;
+}
+
+static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
+ sensor_settings[GAIN_IDX] = val;
+
+ PDEBUG(D_V4L2, "Set gain to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
- err = m5602_read_sensor(sd, S5K4AA_GAIN_2, &data, 1);
- *val = data;
- PDEBUG(D_V4L2, "Read gain %d", *val);
+ data = val & 0xff;
+ err = m5602_write_sensor(sd, S5K4AA_GAIN, &data, 1);
-out:
return err;
}
-int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[BRIGHTNESS_IDX];
+ PDEBUG(D_V4L2, "Read brightness %d", *val);
+ return 0;
+}
+
+static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
- PDEBUG(D_V4L2, "Set gain to %d", val);
+ sensor_settings[BRIGHTNESS_IDX] = val;
+
+ PDEBUG(D_V4L2, "Set brightness to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
- goto out;
+ return err;
data = val & 0xff;
- err = m5602_write_sensor(sd, S5K4AA_GAIN_2, &data, 1);
+ return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
+}
-out:
- return err;
+static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[NOISE_SUPP_IDX];
+ PDEBUG(D_V4L2, "Read noise %d", *val);
+ return 0;
+}
+
+static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+ u8 data = S5K4AA_PAGE_MAP_2;
+ int err;
+
+ sensor_settings[NOISE_SUPP_IDX] = val;
+
+ PDEBUG(D_V4L2, "Set noise to %d", val);
+ err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
+ if (err < 0)
+ return err;
+
+ data = val & 0x01;
+ return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
+}
+
+void s5k4aa_disconnect(struct sd *sd)
+{
+ sd->sensor = NULL;
+ kfree(sd->sensor_priv);
}
static void s5k4aa_dump_registers(struct sd *sd)
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
index 1f88b0d04..4440da4e7 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
@@ -47,8 +47,9 @@
#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 */
-#define S5K4AA_GAIN_2 0x20 /* (analogue?) gain : 7 bits */
+#define S5K4AA_BRIGHTNESS 0x1f /* (digital?) gain : 5 bits */
+#define S5K4AA_GAIN 0x20 /* (analogue?) gain : 7 bits */
+#define S5K4AA_NOISE_SUPP 0x37
#define S5K4AA_RM_ROW_SKIP_4X 0x08
#define S5K4AA_RM_ROW_SKIP_2X 0x04
@@ -57,6 +58,9 @@
#define S5K4AA_RM_H_FLIP 0x40
#define S5K4AA_RM_V_FLIP 0x80
+#define S5K4AA_DEFAULT_GAIN 0x5f
+#define S5K4AA_DEFAULT_BRIGHTNESS 0x10
+
/*****************************************************************************/
/* Kernel module parameters */
@@ -65,95 +69,18 @@ extern int dump_sensor;
int s5k4aa_probe(struct sd *sd);
int s5k4aa_init(struct sd *sd);
-int s5k4aa_power_down(struct sd *sd);
-
-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);
-int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
-int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
-int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+int s5k4aa_start(struct sd *sd);
+void s5k4aa_disconnect(struct sd *sd);
-static struct m5602_sensor s5k4aa = {
+static const struct m5602_sensor s5k4aa = {
.name = "S5K4AA",
- .probe = s5k4aa_probe,
- .init = s5k4aa_init,
- .power_down = s5k4aa_power_down,
.i2c_slave_id = 0x5a,
.i2c_regW = 2,
- .nctrls = 4,
- .ctrls = {
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k4aa_set_vflip,
- .get = s5k4aa_get_vflip
- }, {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k4aa_set_hflip,
- .get = s5k4aa_get_hflip
-
- }, {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 0xa0,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k4aa_set_gain,
- .get = s5k4aa_get_gain
- }, {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 13,
- .maximum = 0xfff,
- .step = 1,
- .default_value = 0x100,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k4aa_set_exposure,
- .get = s5k4aa_get_exposure
- }
- },
-
- .nmodes = 1,
- .modes = {
- {
- M5602_DEFAULT_FRAME_WIDTH,
- M5602_DEFAULT_FRAME_HEIGHT,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
- .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1
- }
- }
+ .probe = s5k4aa_probe,
+ .init = s5k4aa_init,
+ .start = s5k4aa_start,
+ .disconnect = s5k4aa_disconnect,
};
static const unsigned char preinit_s5k4aa[][4] =
@@ -248,30 +175,12 @@ static const unsigned char init_s5k4aa[][4] =
{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
{SENSOR, 0x0c, 0x05, 0x00},
{SENSOR, 0x02, 0x0e, 0x00},
- {SENSOR, S5K4AA_GAIN_1, 0x0f, 0x00},
- {SENSOR, S5K4AA_GAIN_2, 0x00, 0x00},
- {SENSOR, S5K4AA_GLOBAL_GAIN__, 0x01, 0x00},
- {SENSOR, 0x11, 0x00, 0x00},
- {SENSOR, 0x12, 0x00, 0x00},
- {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
{SENSOR, S5K4AA_READ_MODE, 0xa0, 0x00},
{SENSOR, 0x37, 0x00, 0x00},
- {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
- {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
- {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
- {SENSOR, S5K4AA_COLSTART_LO, 0x0b, 0x00},
- {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x03, 0x00},
- {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0xc4, 0x00},
- {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
- {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x08, 0x00},
- {SENSOR, S5K4AA_H_BLANK_HI__, 0x00, 0x00},
- {SENSOR, S5K4AA_H_BLANK_LO__, 0x48, 0x00},
- {SENSOR, S5K4AA_EXPOSURE_HI, 0x00, 0x00},
- {SENSOR, S5K4AA_EXPOSURE_LO, 0x43, 0x00},
- {SENSOR, 0x11, 0x04, 0x00},
- {SENSOR, 0x12, 0xc3, 0x00},
- {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+};
+static const unsigned char VGA_s5k4aa[][4] =
+{
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -307,7 +216,7 @@ static const unsigned char init_s5k4aa[][4] =
{SENSOR, 0x37, 0x01, 0x00},
/* ROWSTART_HI, ROWSTART_LO : 10 + (1024-960)/2 = 42 = 0x002a */
{SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
- {SENSOR, S5K4AA_ROWSTART_LO, 0x2a, 0x00},
+ {SENSOR, S5K4AA_ROWSTART_LO, 0x29, 0x00},
{SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
{SENSOR, S5K4AA_COLSTART_LO, 0x0c, 0x00},
/* window_height_hi, window_height_lo : 960 = 0x03c0 */
@@ -324,9 +233,57 @@ static const unsigned char init_s5k4aa[][4] =
{SENSOR, 0x12, 0xc3, 0x00},
{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
{SENSOR, 0x02, 0x0e, 0x00},
- {SENSOR_LONG, S5K4AA_GLOBAL_GAIN__, 0x0f, 0x00},
- {SENSOR, S5K4AA_GAIN_1, 0x0b, 0x00},
- {SENSOR, S5K4AA_GAIN_2, 0xa0, 0x00}
};
+static const unsigned char SXGA_s5k4aa[][4] =
+{
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
+ {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
+ {BRIDGE, M5602_XB_SENSOR_TYPE, 0x08, 0x00},
+ {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
+ {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
+ {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ /* VSYNC_PARA, VSYNC_PARA : img height 1024 = 0x0400 */
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x04, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+ {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+ /* HSYNC_PARA, HSYNC_PARA : img width 1280 = 0x0500 */
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x05, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00},
+ {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
+ {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xa0, 0x00}, /* 48 MHz */
+
+ {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+ {SENSOR, S5K4AA_READ_MODE, S5K4AA_RM_H_FLIP, 0x00},
+ {SENSOR, 0x37, 0x01, 0x00},
+ {SENSOR, S5K4AA_ROWSTART_HI, 0x00, 0x00},
+ {SENSOR, S5K4AA_ROWSTART_LO, 0x09, 0x00},
+ {SENSOR, S5K4AA_COLSTART_HI, 0x00, 0x00},
+ {SENSOR, S5K4AA_COLSTART_LO, 0x0a, 0x00},
+ {SENSOR, S5K4AA_WINDOW_HEIGHT_HI, 0x04, 0x00},
+ {SENSOR, S5K4AA_WINDOW_HEIGHT_LO, 0x00, 0x00},
+ {SENSOR, S5K4AA_WINDOW_WIDTH_HI, 0x05, 0x00},
+ {SENSOR, S5K4AA_WINDOW_WIDTH_LO, 0x00, 0x00},
+ {SENSOR, S5K4AA_H_BLANK_HI__, 0x01, 0x00},
+ {SENSOR, S5K4AA_H_BLANK_LO__, 0xa8, 0x00},
+ {SENSOR, S5K4AA_EXPOSURE_HI, 0x01, 0x00},
+ {SENSOR, S5K4AA_EXPOSURE_LO, 0x00, 0x00},
+ {SENSOR, 0x11, 0x04, 0x00},
+ {SENSOR, 0x12, 0xc3, 0x00},
+ {SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
+ {SENSOR, 0x02, 0x0e, 0x00},
+};
+
+
#endif
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c
index ccea4a758..7127321ac 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -16,12 +16,120 @@
*
*/
+#include <linux/kthread.h>
#include "m5602_s5k83a.h"
+static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
+static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
+
+static struct v4l2_pix_format s5k83a_modes[] = {
+ {
+ 640,
+ 480,
+ V4L2_PIX_FMT_SBGGR8,
+ V4L2_FIELD_NONE,
+ .sizeimage =
+ 640 * 480,
+ .bytesperline = 640,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0
+ }
+};
+
+static const struct ctrl s5k83a_ctrls[] = {
+#define GAIN_IDX 0
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x01,
+ .default_value = S5K83A_DEFAULT_GAIN,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = s5k83a_set_gain,
+ .get = s5k83a_get_gain
+
+ },
+#define BRIGHTNESS_IDX 1
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "brightness",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x01,
+ .default_value = S5K83A_DEFAULT_BRIGHTNESS,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = s5k83a_set_brightness,
+ .get = s5k83a_get_brightness,
+ },
+#define EXPOSURE_IDX 2
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x00,
+ .maximum = S5K83A_MAXIMUM_EXPOSURE,
+ .step = 0x01,
+ .default_value = S5K83A_DEFAULT_EXPOSURE,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = s5k83a_set_exposure,
+ .get = s5k83a_get_exposure
+ },
+#define HFLIP_IDX 3
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = s5k83a_set_hflip,
+ .get = s5k83a_get_hflip
+ },
+#define VFLIP_IDX 4
+ {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
+ },
+ .set = s5k83a_set_vflip,
+ .get = s5k83a_get_vflip
+ }
+};
+
static void s5k83a_dump_registers(struct sd *sd);
+static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
+static int s5k83a_set_led_indication(struct sd *sd, u8 val);
+static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
+ __s32 vflip, __s32 hflip);
int s5k83a_probe(struct sd *sd)
{
+ struct s5k83a_priv *sens_priv;
u8 prod_id = 0, ver_id = 0;
int i, err = 0;
@@ -63,16 +171,36 @@ int s5k83a_probe(struct sd *sd)
info("Detected a s5k83a sensor");
sensor_found:
- sd->gspca_dev.cam.cam_mode = s5k83a.modes;
- sd->gspca_dev.cam.nmodes = s5k83a.nmodes;
- sd->desc->ctrls = s5k83a.ctrls;
- sd->desc->nctrls = s5k83a.nctrls;
+ sens_priv = kmalloc(
+ sizeof(struct s5k83a_priv), GFP_KERNEL);
+ if (!sens_priv)
+ return -ENOMEM;
+
+ sens_priv->settings =
+ kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
+ if (!sens_priv->settings)
+ return -ENOMEM;
+
+ sd->gspca_dev.cam.cam_mode = s5k83a_modes;
+ sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
+ sd->desc->ctrls = s5k83a_ctrls;
+ sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
+
+ /* null the pointer! thread is't running now */
+ sens_priv->rotation_thread = NULL;
+
+ for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
+ sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
+
+ sd->sensor_priv = sens_priv;
return 0;
}
int s5k83a_init(struct sd *sd)
{
int i, err = 0;
+ s32 *sensor_settings =
+ ((struct s5k83a_priv *) sd->sensor_priv)->settings;
for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
u8 data[2] = {0x00, 0x00};
@@ -105,180 +233,216 @@ int s5k83a_init(struct sd *sd)
if (dump_sensor)
s5k83a_dump_registers(sd);
- return (err < 0) ? err : 0;
+ err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
+ if (err < 0)
+ return err;
+
+ err = s5k83a_set_brightness(&sd->gspca_dev,
+ sensor_settings[BRIGHTNESS_IDX]);
+ if (err < 0)
+ return err;
+
+ err = s5k83a_set_exposure(&sd->gspca_dev,
+ sensor_settings[EXPOSURE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
+ if (err < 0)
+ return err;
+
+ err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
+
+ return err;
}
-int s5k83a_power_down(struct sd *sd)
+static int rotation_thread_function(void *data)
{
+ struct sd *sd = (struct sd *) data;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
+ u8 reg, previous_rotation = 0;
+ __s32 vflip, hflip;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (!schedule_timeout(100)) {
+ if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
+ break;
+
+ s5k83a_get_rotation(sd, &reg);
+ if (previous_rotation != reg) {
+ previous_rotation = reg;
+ info("Camera was flipped");
+
+ s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
+ s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+
+ if (reg) {
+ vflip = !vflip;
+ hflip = !hflip;
+ }
+ s5k83a_set_flip_real((struct gspca_dev *) sd,
+ vflip, hflip);
+ }
+
+ mutex_unlock(&sd->gspca_dev.usb_lock);
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+
+ /* return to "front" flip */
+ if (previous_rotation) {
+ s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
+ s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
+ s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
+ }
+
+ sens_priv->rotation_thread = NULL;
return 0;
}
-static void s5k83a_dump_registers(struct sd *sd)
+int s5k83a_start(struct sd *sd)
{
- int address;
- u8 page, old_page;
- m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+ int i, err = 0;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
- for (page = 0; page < 16; page++) {
- 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;
- m5602_read_sensor(sd, address, &val, 1);
- info("register 0x%x contains 0x%x",
- address, val);
- }
+ /* Create another thread, polling the GPIO ports of the camera to check
+ if it got rotated. This is how the windows driver does it so we have
+ to assume that there is no better way of accomplishing this */
+ sens_priv->rotation_thread = kthread_create(rotation_thread_function,
+ sd, "rotation thread");
+ wake_up_process(sens_priv->rotation_thread);
+
+ /* Preinit the sensor */
+ for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
+ u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};
+ if (start_s5k83a[i][0] == SENSOR)
+ err = m5602_write_sensor(sd, start_s5k83a[i][1],
+ data, 2);
+ else
+ err = m5602_write_bridge(sd, start_s5k83a[i][1],
+ data[0]);
}
- info("s5k83a register state dump complete");
+ if (err < 0)
+ return err;
- for (page = 0; page < 16; page++) {
- 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;
+ return s5k83a_set_led_indication(sd, 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);
+int s5k83a_stop(struct sd *sd)
+{
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
- if (ctrl_val == test_val)
- info("register 0x%x is writeable", address);
- else
- info("register 0x%x is read only", address);
+ if (sens_priv->rotation_thread)
+ kthread_stop(sens_priv->rotation_thread);
- /* Restore original val */
- m5602_write_sensor(sd, address, &old_val, 1);
- }
- }
- info("Read/write register probing complete");
- m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+ return s5k83a_set_led_indication(sd, 0);
}
-int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
+void s5k83a_disconnect(struct sd *sd)
{
- int err;
- u8 data[2];
- struct sd *sd = (struct sd *) gspca_dev;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
- err = m5602_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
- if (err < 0)
- goto out;
+ s5k83a_stop(sd);
- data[1] = data[1] << 1;
- *val = data[1];
+ sd->sensor = NULL;
+ kfree(sens_priv->settings);
+ kfree(sens_priv);
+}
-out:
- return err;
+static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
+
+ *val = sens_priv->settings[GAIN_IDX];
+ return 0;
}
-int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
+
+ sens_priv->settings[GAIN_IDX] = val;
data[0] = 0x00;
data[1] = 0x20;
err = m5602_write_sensor(sd, 0x14, data, 2);
if (err < 0)
- goto out;
+ return err;
data[0] = 0x01;
data[1] = 0x00;
err = m5602_write_sensor(sd, 0x0d, data, 2);
if (err < 0)
- goto out;
+ return err;
/* 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 = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
+ data[0] = val >> 3; /* gain, high 5 bits */
+ data[1] = val >> 1; /* gain, high 7 bits */
+ err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
-out:
return err;
}
-int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 data;
struct sd *sd = (struct sd *) gspca_dev;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
- err = m5602_read_sensor(sd, S5K83A_WHITENESS, &data, 1);
- if (err < 0)
- goto out;
-
- *val = data;
-
-out:
- return err;
+ *val = sens_priv->settings[BRIGHTNESS_IDX];
+ return 0;
}
-int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 data[1];
struct sd *sd = (struct sd *) gspca_dev;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
+ sens_priv->settings[BRIGHTNESS_IDX] = val;
data[0] = val;
- err = m5602_write_sensor(sd, S5K83A_WHITENESS, data, 1);
-
+ err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
return err;
}
-int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
- 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)
- data[1] = S5K83A_MAXIMUM_GAIN;
-
- *val = data[1];
-
-out:
- return err;
+ *val = sens_priv->settings[EXPOSURE_IDX];
+ return 0;
}
-int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 data[2];
struct sd *sd = (struct sd *) gspca_dev;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
+ sens_priv->settings[EXPOSURE_IDX] = val;
data[0] = 0;
data[1] = val;
- err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
+ err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
return err;
}
-int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
{
- int err;
- u8 data[1];
struct sd *sd = (struct sd *) gspca_dev;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
- data[0] = 0x05;
- err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
- if (err < 0)
- goto out;
-
- err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
- *val = (data[0] | 0x40) ? 1 : 0;
-
-out:
- return err;
+ *val = sens_priv->settings[VFLIP_IDX];
+ return 0;
}
-int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
+ __s32 vflip, __s32 hflip)
{
int err;
u8 data[1];
@@ -287,68 +451,149 @@ int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
data[0] = 0x05;
err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
if (err < 0)
- goto out;
+ return err;
- err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
- if (err < 0)
- goto out;
+ /* six bit is vflip, seven is hflip */
+ data[0] = S5K83A_FLIP_MASK;
+ data[0] = (vflip) ? data[0] | 0x40 : data[0];
+ data[0] = (hflip) ? data[0] | 0x80 : data[0];
- /* 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 = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
if (err < 0)
- goto out;
+ return err;
- data[0] = (val) ? 0x0b : 0x0a;
+ data[0] = (vflip) ? 0x0b : 0x0a;
err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
+ if (err < 0)
+ return err;
-out:
+ data[0] = (hflip) ? 0x0a : 0x0b;
+ err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
return err;
}
-int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
- u8 data[1];
+ u8 reg;
+ __s32 hflip;
struct sd *sd = (struct sd *) gspca_dev;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
- data[0] = 0x05;
- err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
- if (err < 0)
- goto out;
+ sens_priv->settings[VFLIP_IDX] = val;
- err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
- *val = (data[0] | 0x80) ? 1 : 0;
+ s5k83a_get_hflip(gspca_dev, &hflip);
+
+ err = s5k83a_get_rotation(sd, &reg);
+ if (err < 0)
+ return err;
+ if (reg) {
+ val = !val;
+ hflip = !hflip;
+ }
-out:
+ err = s5k83a_set_flip_real(gspca_dev, val, hflip);
return err;
}
-int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
+static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
+
+ *val = sens_priv->settings[HFLIP_IDX];
+ return 0;
+}
+
+static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
- u8 data[1];
+ u8 reg;
+ __s32 vflip;
struct sd *sd = (struct sd *) gspca_dev;
+ struct s5k83a_priv *sens_priv = sd->sensor_priv;
- data[0] = 0x05;
- err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
- if (err < 0)
- goto out;
+ sens_priv->settings[HFLIP_IDX] = val;
+
+ s5k83a_get_vflip(gspca_dev, &vflip);
- err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
+ err = s5k83a_get_rotation(sd, &reg);
if (err < 0)
- goto out;
+ return err;
+ if (reg) {
+ val = !val;
+ vflip = !vflip;
+ }
- /* 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 = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
+ err = s5k83a_set_flip_real(gspca_dev, vflip, val);
+ return err;
+}
+
+static int s5k83a_set_led_indication(struct sd *sd, u8 val)
+{
+ int err = 0;
+ u8 data[1];
+
+ err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
if (err < 0)
- goto out;
+ return err;
- data[0] = (val) ? 0x0a : 0x0b;
- err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
-out:
+ if (val)
+ data[0] = data[0] | S5K83A_GPIO_LED_MASK;
+ else
+ data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
+
+ err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
+
+ return err;
+}
+
+/* Get camera rotation on Acer notebooks */
+static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
+{
+ int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
+ *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
return err;
}
+
+static void s5k83a_dump_registers(struct sd *sd)
+{
+ int address;
+ u8 page, old_page;
+ m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+
+ for (page = 0; page < 16; page++) {
+ 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;
+ m5602_read_sensor(sd, address, &val, 1);
+ info("register 0x%x contains 0x%x",
+ address, val);
+ }
+ }
+ info("s5k83a register state dump complete");
+
+ for (page = 0; page < 16; page++) {
+ 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;
+
+ 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);
+ else
+ info("register 0x%x is read only", address);
+
+ /* Restore original val */
+ m5602_write_sensor(sd, address, &old_val, 1);
+ }
+ }
+ info("Read/write register probing complete");
+ m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
+}
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h
index 05ccb5b57..7814b078a 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_s5k83a.h
@@ -21,20 +21,21 @@
#include "m5602_sensor.h"
-#define S5K83A_FLIP 0x01
-#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_DEFAULT_BRIGHTNESS 0x71
-#define S5K83A_DEFAULT_WHITENESS 0x7e
-#define S5K83A_DEFAULT_GAIN 0x00
-#define S5K83A_MAXIMUM_GAIN 0x3c
-#define S5K83A_FLIP_MASK 0x10
-
+#define S5K83A_FLIP 0x01
+#define S5K83A_HFLIP_TUNE 0x03
+#define S5K83A_VFLIP_TUNE 0x05
+#define S5K83A_BRIGHTNESS 0x0a
+#define S5K83A_EXPOSURE 0x18
+#define S5K83A_GAIN 0x1b
+#define S5K83A_PAGE_MAP 0xec
+
+#define S5K83A_DEFAULT_GAIN 0x71
+#define S5K83A_DEFAULT_BRIGHTNESS 0x7e
+#define S5K83A_DEFAULT_EXPOSURE 0x00
+#define S5K83A_MAXIMUM_EXPOSURE 0x3c
+#define S5K83A_FLIP_MASK 0x10
+#define S5K83A_GPIO_LED_MASK 0x10
+#define S5K83A_GPIO_ROTATION_MASK 0x40
/*****************************************************************************/
@@ -44,108 +45,26 @@ extern int dump_sensor;
int s5k83a_probe(struct sd *sd);
int s5k83a_init(struct sd *sd);
-int s5k83a_power_down(struct sd *sd);
-
-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);
-int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
-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);
+int s5k83a_start(struct sd *sd);
+int s5k83a_stop(struct sd *sd);
+void s5k83a_disconnect(struct sd *sd);
-static struct m5602_sensor s5k83a = {
+static const struct m5602_sensor s5k83a = {
.name = "S5K83A",
.probe = s5k83a_probe,
.init = s5k83a_init,
- .power_down = s5k83a_power_down,
+ .start = s5k83a_start,
+ .stop = s5k83a_stop,
+ .disconnect = s5k83a_disconnect,
.i2c_slave_id = 0x5a,
.i2c_regW = 2,
- .nctrls = 5,
- .ctrls = {
- {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "brightness",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_BRIGHTNESS,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_brightness,
- .get = s5k83a_get_brightness
+};
- }, {
- {
- .id = V4L2_CID_WHITENESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "whiteness",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_WHITENESS,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_whiteness,
- .get = s5k83a_get_whiteness,
- }, {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = S5K83A_MAXIMUM_GAIN,
- .step = 0x01,
- .default_value = S5K83A_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
- },
- .set = s5k83a_set_gain,
- .get = s5k83a_get_gain
- }, {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k83a_set_hflip,
- .get = s5k83a_get_hflip
- }, {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
- },
- .set = s5k83a_set_vflip,
- .get = s5k83a_get_vflip
- }
- },
- .nmodes = 1,
- .modes = {
- {
- M5602_DEFAULT_FRAME_WIDTH,
- M5602_DEFAULT_FRAME_HEIGHT,
- V4L2_PIX_FMT_SBGGR8,
- V4L2_FIELD_NONE,
- .sizeimage =
- M5602_DEFAULT_FRAME_WIDTH * M5602_DEFAULT_FRAME_HEIGHT,
- .bytesperline = M5602_DEFAULT_FRAME_WIDTH,
- .colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1
- }
- }
+struct s5k83a_priv {
+ /* We use another thread periodically
+ probing the orientation of the camera */
+ struct task_struct *rotation_thread;
+ s32 *settings;
};
static const unsigned char preinit_s5k83a[][4] =
@@ -184,8 +103,6 @@ static const unsigned char preinit_s5k83a[][4] =
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
{BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
-
- {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00}
};
/* This could probably be considerably shortened.
@@ -193,86 +110,8 @@ static const unsigned char preinit_s5k83a[][4] =
*/
static const unsigned char init_s5k83a[][4] =
{
- {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
- {SENSOR, 0xaf, 0x01, 0x00},
- {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
- {SENSOR, 0x7b, 0xff, 0x00},
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
- {SENSOR, 0x01, 0x50, 0x00},
- {SENSOR, 0x12, 0x20, 0x00},
- {SENSOR, 0x17, 0x40, 0x00},
- {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
- {SENSOR, 0x1c, 0x00, 0x00},
- {SENSOR, 0x02, 0x70, 0x00},
- {SENSOR, 0x03, 0x0b, 0x00},
- {SENSOR, 0x04, 0xf0, 0x00},
- {SENSOR, 0x05, 0x0b, 0x00},
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {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, 0x87, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
- {SENSOR, 0x06, 0x71, 0x00},
- {SENSOR, 0x07, 0xe8, 0x00},
- {SENSOR, 0x08, 0x02, 0x00},
- {SENSOR, 0x09, 0x88, 0x00},
- {SENSOR, 0x14, 0x00, 0x00},
- {SENSOR, 0x15, 0x20, 0x00},
- {SENSOR, 0x19, 0x00, 0x00},
- {SENSOR, 0x1a, 0x98, 0x00},
- {SENSOR, 0x0f, 0x02, 0x00},
- {SENSOR, 0x10, 0xe5, 0x00},
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
- {SENSOR_LONG, 0x14, 0x00, 0x20},
- {SENSOR_LONG, 0x0d, 0x00, 0x7d},
- {SENSOR_LONG, 0x1b, 0x0d, 0x05},
-
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {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, 0x87, 0x00},
-
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
+ /* The following sequence is useless after a clean boot
+ but is necessary after resume from suspend */
{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
{BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
{BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
@@ -292,7 +131,7 @@ static const unsigned char init_s5k83a[][4] =
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
+ {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
{BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
{BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
@@ -301,109 +140,34 @@ static const unsigned char init_s5k83a[][4] =
{SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
{SENSOR, 0xaf, 0x01, 0x00},
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
- /* ff ( init value )is very dark) || 71 and f0 better */
+ {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
{SENSOR, 0x7b, 0xff, 0x00},
{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
{SENSOR, 0x01, 0x50, 0x00},
{SENSOR, 0x12, 0x20, 0x00},
{SENSOR, 0x17, 0x40, 0x00},
- {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
{SENSOR, 0x1c, 0x00, 0x00},
{SENSOR, 0x02, 0x70, 0x00},
- /* some values like 0x10 give a blue-purple image */
{SENSOR, 0x03, 0x0b, 0x00},
{SENSOR, 0x04, 0xf0, 0x00},
{SENSOR, 0x05, 0x0b, 0x00},
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
-
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
- /* under 80 don't work, highter depend on value */
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00},
- {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00},
- {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
- {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, 0x7f, 0x00},
-
- {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
{SENSOR, 0x06, 0x71, 0x00},
- {SENSOR, 0x07, 0xe8, 0x00},
+ {SENSOR, 0x07, 0xe8, 0x00}, /* 488 */
{SENSOR, 0x08, 0x02, 0x00},
- {SENSOR, 0x09, 0x88, 0x00},
+ {SENSOR, 0x09, 0x88, 0x00}, /* 648 */
{SENSOR, 0x14, 0x00, 0x00},
- {SENSOR, 0x15, 0x20, 0x00},
+ {SENSOR, 0x15, 0x20, 0x00}, /* 32 */
{SENSOR, 0x19, 0x00, 0x00},
- {SENSOR, 0x1a, 0x98, 0x00},
+ {SENSOR, 0x1a, 0x98, 0x00}, /* 152 */
{SENSOR, 0x0f, 0x02, 0x00},
- {SENSOR, 0x10, 0xe5, 0x00},
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
- {SENSOR_LONG, 0x14, 0x00, 0x20},
- {SENSOR_LONG, 0x0d, 0x00, 0x7d},
- {SENSOR_LONG, 0x1b, 0x0d, 0x05},
-
- /* The following sequence is useless after a clean boot
- but is necessary after resume from suspend */
- {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
- {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00},
- {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
- {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
- {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00},
- {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00},
- {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00},
- {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00},
- {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00},
-
- {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00},
- {SENSOR, 0xaf, 0x01, 0x00},
- {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00},
- {SENSOR, 0x7b, 0xff, 0x00},
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
- {SENSOR, 0x01, 0x50, 0x00},
- {SENSOR, 0x12, 0x20, 0x00},
- {SENSOR, 0x17, 0x40, 0x00},
- {SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
- {SENSOR, 0x1c, 0x00, 0x00},
- {SENSOR, 0x02, 0x70, 0x00},
- {SENSOR, 0x03, 0x0b, 0x00},
- {SENSOR, 0x04, 0xf0, 0x00},
- {SENSOR, 0x05, 0x0b, 0x00},
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
+ {SENSOR, 0x10, 0xe5, 0x00}, /* 741 */
+ /* normal colors
+ (this is value after boot, but after tries can be different) */
+ {SENSOR, 0x00, 0x06, 0x00},
+};
+static const unsigned char start_s5k83a[][4] =
+{
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -416,7 +180,7 @@ static const unsigned char init_s5k83a[][4] =
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
{BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00},
- {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00},
+ {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
@@ -424,50 +188,10 @@ static const unsigned char init_s5k83a[][4] =
{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, 0x7f, 0x00},
+ {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */
{BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
-
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
- {SENSOR, 0x06, 0x71, 0x00},
- {SENSOR, 0x07, 0xe8, 0x00},
- {SENSOR, 0x08, 0x02, 0x00},
- {SENSOR, 0x09, 0x88, 0x00},
- {SENSOR, 0x14, 0x00, 0x00},
- {SENSOR, 0x15, 0x20, 0x00},
- {SENSOR, 0x19, 0x00, 0x00},
- {SENSOR, 0x1a, 0x98, 0x00},
- {SENSOR, 0x0f, 0x02, 0x00},
-
- {SENSOR, 0x10, 0xe5, 0x00},
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
- {SENSOR_LONG, 0x14, 0x00, 0x20},
- {SENSOR_LONG, 0x0d, 0x00, 0x7d},
- {SENSOR_LONG, 0x1b, 0x0d, 0x05},
-
- /* normal colors
- (this is value after boot, but after tries can be different) */
- {SENSOR, 0x00, 0x06, 0x00},
-
- /* set default brightness */
- {SENSOR_LONG, 0x14, 0x00, 0x20},
- {SENSOR_LONG, 0x0d, 0x01, 0x00},
- {SENSOR_LONG, 0x1b, S5K83A_DEFAULT_BRIGHTNESS >> 3,
- S5K83A_DEFAULT_BRIGHTNESS >> 1},
-
- /* set default whiteness */
- {SENSOR, S5K83A_WHITENESS, S5K83A_DEFAULT_WHITENESS, 0x00},
-
- /* set default gain */
- {SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_GAIN},
-
- /* set default flip */
- {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
- {SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00},
- {SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00},
- {SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00}
-
};
#endif
diff --git a/linux/drivers/media/video/gspca/m5602/m5602_sensor.h b/linux/drivers/media/video/gspca/m5602/m5602_sensor.h
index 261623f0d..edff4f1f5 100644
--- a/linux/drivers/media/video/gspca/m5602/m5602_sensor.h
+++ b/linux/drivers/media/video/gspca/m5602/m5602_sensor.h
@@ -21,10 +21,8 @@
#include "m5602_bridge.h"
-#define M5602_DEFAULT_FRAME_WIDTH 640
-#define M5602_DEFAULT_FRAME_HEIGHT 480
-
-#define M5602_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
+#define M5602_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 0)
+#define M5602_V4L2_CID_NOISE_SUPPRESION (V4L2_CID_PRIVATE_BASE + 1)
/* Enumerates all supported sensors */
enum sensors {
@@ -32,7 +30,8 @@ enum sensors {
S5K83A_SENSOR = 2,
S5K4AA_SENSOR = 3,
MT9M111_SENSOR = 4,
- PO1030_SENSOR = 5
+ PO1030_SENSOR = 5,
+ OV7660_SENSOR = 6,
};
/* Enumerates all possible instruction types */
@@ -61,14 +60,11 @@ struct m5602_sensor {
/* Executed when the camera starts to send data */
int (*start)(struct sd *sd);
- /* Performs a power down sequence */
- int (*power_down)(struct sd *sd);
-
- int nctrls;
- struct ctrl ctrls[M5602_MAX_CTRLS];
+ /* Executed when the camera ends to send data */
+ int (*stop)(struct sd *sd);
- char nmodes;
- struct v4l2_pix_format modes[];
+ /* Executed when the device is disconnected */
+ void (*disconnect)(struct sd *sd);
};
#endif
diff --git a/linux/drivers/media/video/gspca/mars.c b/linux/drivers/media/video/gspca/mars.c
index 5d54893eb..789fd178a 100644
--- a/linux/drivers/media/video/gspca/mars.c
+++ b/linux/drivers/media/video/gspca/mars.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "mars"
#include "gspca.h"
-#define QUANT_VAL 1 /* quantization table */
#include "jpeg.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
@@ -37,6 +36,12 @@ struct sd {
u8 colors;
u8 gamma;
u8 sharpness;
+ u8 quality;
+#define QUALITY_MIN 40
+#define QUALITY_MAX 70
+#define QUALITY_DEF 50
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -176,6 +181,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->colors = COLOR_DEF;
sd->gamma = GAMMA_DEF;
sd->sharpness = SHARPNESS_DEF;
+ sd->quality = QUALITY_DEF;
gspca_dev->nbalt = 9; /* use the altsetting 08 */
return 0;
}
@@ -193,6 +199,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
u8 *data;
int i;
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x21); /* JPEG 422 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
data = gspca_dev->usb_buf;
data[0] = 0x01; /* address */
@@ -341,11 +353,19 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
PDEBUG(D_ERR, "Camera Stop failed");
}
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ kfree(sd->jpeg_hdr);
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
int p;
if (len < 6) {
@@ -368,7 +388,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
frame, data, p);
/* put the JPEG header */
- jpeg_put_header(gspca_dev, frame, 0x21);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
data += p + 16;
len -= p + 16;
break;
@@ -465,6 +486,34 @@ static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -474,7 +523,10 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
diff --git a/linux/drivers/media/video/gspca/mr97310a.c b/linux/drivers/media/video/gspca/mr97310a.c
index 5ec5ce6e3..301325134 100644
--- a/linux/drivers/media/video/gspca/mr97310a.c
+++ b/linux/drivers/media/video/gspca/mr97310a.c
@@ -29,9 +29,7 @@ MODULE_LICENSE("GPL");
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
-
u8 sof_read;
- u8 header_read;
};
/* V4L2 controls supported by the driver */
@@ -285,7 +283,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
- struct sd *sd = (struct sd *) gspca_dev;
unsigned char *sof;
sof = pac_find_sof(gspca_dev, data, len);
@@ -300,25 +297,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
n = 0;
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
data, n);
- sd->header_read = 0;
- gspca_frame_add(gspca_dev, FIRST_PACKET, frame, NULL, 0);
+ /* Start next frame. */
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ pac_sof_marker, sizeof pac_sof_marker);
len -= sof - data;
data = sof;
}
- if (sd->header_read < 7) {
- int needed;
-
- /* skip the rest of the header */
- needed = 7 - sd->header_read;
- if (len <= needed) {
- sd->header_read += len;
- return;
- }
- data += needed;
- len -= needed;
- sd->header_read = 7;
- }
-
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
@@ -337,6 +321,7 @@ static const struct sd_desc sd_desc = {
/* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x08ca, 0x0111)},
+ {USB_DEVICE(0x093a, 0x010f)},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
@@ -363,8 +348,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- if (usb_register(&sd_driver) < 0)
- return -1;
+ int ret;
+
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
PDEBUG(D_PROBE, "registered");
return 0;
}
diff --git a/linux/drivers/media/video/gspca/ov534.c b/linux/drivers/media/video/gspca/ov534.c
index de0ab8e06..14341b6be 100644
--- a/linux/drivers/media/video/gspca/ov534.c
+++ b/linux/drivers/media/video/gspca/ov534.c
@@ -1,7 +1,8 @@
/*
- * ov534/ov772x gspca driver
+ * ov534 gspca driver
* Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it>
* Copyright (C) 2008 Jim Paris <jim@jtan.com>
+ * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr
*
* Based on a prototype written by Mark Ferrell <majortrips@gmail.com>
* USB protocol reverse engineered by Jim Paris <jim@jtan.com>
@@ -26,7 +27,7 @@
#include "gspca.h"
-#define OV534_REG_ADDRESS 0xf1 /* ? */
+#define OV534_REG_ADDRESS 0xf1 /* sensor address */
#define OV534_REG_SUBADDR 0xf2
#define OV534_REG_WRITE 0xf3
#define OV534_REG_READ 0xf4
@@ -46,131 +47,41 @@ MODULE_LICENSE("GPL");
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u32 last_fid;
__u32 last_pts;
- int frame_rate;
+ u16 last_fid;
+ u8 frame_rate;
+
+ u8 sensor;
+#define SENSOR_OV772X 0
+#define SENSOR_OV965X 1
};
/* V4L2 controls supported by the driver */
static struct ctrl sd_ctrls[] = {
};
-static const struct v4l2_pix_format vga_mode[] = {
+static const struct v4l2_pix_format vga_yuyv_mode[] = {
{640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
.bytesperline = 640 * 2,
.sizeimage = 640 * 480 * 2,
- .colorspace = V4L2_COLORSPACE_JPEG,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0},
};
-static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
-{
- struct usb_device *udev = gspca_dev->dev;
- int ret;
-
- 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, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
- if (ret < 0)
- PDEBUG(D_ERR, "write failed");
-}
-
-static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
-{
- 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, 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 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 gspca_dev *gspca_dev, int status)
-{
- u8 data;
-
- PDEBUG(D_CONF, "led status: %d", status);
-
- data = ov534_reg_read(gspca_dev, 0x21);
- data |= 0x80;
- ov534_reg_write(gspca_dev, 0x21, data);
-
- data = ov534_reg_read(gspca_dev, 0x23);
- if (status)
- data |= 0x80;
- else
- data &= ~(0x80);
-
- ov534_reg_write(gspca_dev, 0x23, data);
-}
-
-static int sccb_check_status(struct gspca_dev *gspca_dev)
-{
- u8 data;
- int i;
-
- for (i = 0; i < 5; i++) {
- data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);
-
- switch (data) {
- case 0x00:
- return 1;
- case 0x04:
- return 0;
- case 0x03:
- break;
- default:
- PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
- data, i + 1);
- }
- }
- return 0;
-}
-
-static void sccb_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
-{
- 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(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 */
+static const struct v4l2_pix_format vga_jpeg_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 0},
+};
+static const u8 bridge_init_ov722x[][2] = {
{ 0xc2, 0x0c },
{ 0x88, 0xf8 },
{ 0xc3, 0x69 },
@@ -228,7 +139,7 @@ static const __u8 ov534_reg_initdata[][2] = {
{ 0xc2, 0x0c },
};
-static const __u8 ov772x_reg_initdata[][2] = {
+static const u8 sensor_init_ov722x[][2] = {
{ 0x12, 0x80 },
{ 0x11, 0x01 },
@@ -311,6 +222,547 @@ static const __u8 ov772x_reg_initdata[][2] = {
{ 0x0c, 0xd0 }
};
+static const u8 bridge_init_ov965x[][2] = {
+ {0x88, 0xf8},
+ {0x89, 0xff},
+ {0x76, 0x03},
+ {0x92, 0x03},
+ {0x95, 0x10},
+ {0xe2, 0x00},
+ {0xe7, 0x3e},
+ {0x8d, 0x1c},
+ {0x8e, 0x00},
+ {0x8f, 0x00},
+ {0x1f, 0x00},
+ {0xc3, 0xf9},
+ {0x89, 0xff},
+ {0x88, 0xf8},
+ {0x76, 0x03},
+ {0x92, 0x01},
+ {0x93, 0x18},
+ {0x1c, 0x0a},
+ {0x1d, 0x48},
+ {0xc0, 0x50},
+ {0xc1, 0x3c},
+ {0x34, 0x05},
+ {0xc2, 0x0c},
+ {0xc3, 0xf9},
+ {0x34, 0x05},
+ {0xe7, 0x2e},
+ {0x31, 0xf9},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x25, 0x42},
+ {0x94, 0x11},
+};
+
+static const u8 sensor_init_ov965x[][2] = {
+ {0x12, 0x80}, /* com7 - SSCB reset */
+ {0x00, 0x00}, /* gain */
+ {0x01, 0x80}, /* blue */
+ {0x02, 0x80}, /* red */
+ {0x03, 0x1b}, /* vref */
+ {0x04, 0x03}, /* com1 - exposure low bits */
+ {0x0b, 0x57}, /* ver */
+ {0x0e, 0x61}, /* com5 */
+ {0x0f, 0x42}, /* com6 */
+ {0x11, 0x00}, /* clkrc */
+ {0x12, 0x02}, /* com7 - 15fps VGA YUYV */
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x14, 0x28}, /* com9 */
+ {0x16, 0x24}, /* reg16 */
+ {0x17, 0x1d}, /* hstart*/
+ {0x18, 0xbd}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x81}, /* vstop*/
+ {0x1e, 0x04}, /* mvfp */
+ {0x24, 0x3c}, /* aew */
+ {0x25, 0x36}, /* aeb */
+ {0x26, 0x71}, /* vpt */
+ {0x27, 0x08}, /* bbias */
+ {0x28, 0x08}, /* gbbias */
+ {0x29, 0x15}, /* gr com */
+ {0x2a, 0x00}, /* exhch */
+ {0x2b, 0x00}, /* exhcl */
+ {0x2c, 0x08}, /* rbias */
+ {0x32, 0xff}, /* href */
+ {0x33, 0x00}, /* chlf */
+ {0x34, 0x3f}, /* aref1 */
+ {0x35, 0x00}, /* aref2 */
+ {0x36, 0xf8}, /* aref3 */
+ {0x38, 0x72}, /* adc2 */
+ {0x39, 0x57}, /* aref4 */
+ {0x3a, 0x80}, /* tslb - yuyv */
+ {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
+ {0x3d, 0x99}, /* com13 */
+ {0x3f, 0xc1}, /* edge */
+ {0x40, 0xc0}, /* com15 */
+ {0x41, 0x40}, /* com16 */
+ {0x42, 0xc0}, /* com17 */
+ {0x43, 0x0a}, /* rsvd */
+ {0x44, 0xf0},
+ {0x45, 0x46},
+ {0x46, 0x62},
+ {0x47, 0x2a},
+ {0x48, 0x3c},
+ {0x4a, 0xfc},
+ {0x4b, 0xfc},
+ {0x4c, 0x7f},
+ {0x4d, 0x7f},
+ {0x4e, 0x7f},
+ {0x4f, 0x98}, /* matrix */
+ {0x50, 0x98},
+ {0x51, 0x00},
+ {0x52, 0x28},
+ {0x53, 0x70},
+ {0x54, 0x98},
+ {0x58, 0x1a}, /* matrix coef sign */
+ {0x59, 0x85}, /* AWB control */
+ {0x5a, 0xa9},
+ {0x5b, 0x64},
+ {0x5c, 0x84},
+ {0x5d, 0x53},
+ {0x5e, 0x0e},
+ {0x5f, 0xf0}, /* AWB blue limit */
+ {0x60, 0xf0}, /* AWB red limit */
+ {0x61, 0xf0}, /* AWB green limit */
+ {0x62, 0x00}, /* lcc1 */
+ {0x63, 0x00}, /* lcc2 */
+ {0x64, 0x02}, /* lcc3 */
+ {0x65, 0x16}, /* lcc4 */
+ {0x66, 0x01}, /* lcc5 */
+ {0x69, 0x02}, /* hv */
+ {0x6b, 0x5a}, /* dbvl */
+ {0x6c, 0x04},
+ {0x6d, 0x55},
+ {0x6e, 0x00},
+ {0x6f, 0x9d},
+ {0x70, 0x21}, /* dnsth */
+ {0x71, 0x78},
+ {0x72, 0x00}, /* poidx */
+ {0x73, 0x01}, /* pckdv */
+ {0x74, 0x3a}, /* xindx */
+ {0x75, 0x35}, /* yindx */
+ {0x76, 0x01},
+ {0x77, 0x02},
+ {0x7a, 0x12}, /* gamma curve */
+ {0x7b, 0x08},
+ {0x7c, 0x16},
+ {0x7d, 0x30},
+ {0x7e, 0x5e},
+ {0x7f, 0x72},
+ {0x80, 0x82},
+ {0x81, 0x8e},
+ {0x82, 0x9a},
+ {0x83, 0xa4},
+ {0x84, 0xac},
+ {0x85, 0xb8},
+ {0x86, 0xc3},
+ {0x87, 0xd6},
+ {0x88, 0xe6},
+ {0x89, 0xf2},
+ {0x8a, 0x03},
+ {0x8c, 0x89}, /* com19 */
+ {0x14, 0x28}, /* com9 */
+ {0x90, 0x7d},
+ {0x91, 0x7b},
+ {0x9d, 0x03}, /* lcc6 */
+ {0x9e, 0x04}, /* lcc7 */
+ {0x9f, 0x7a},
+ {0xa0, 0x79},
+ {0xa1, 0x40}, /* aechm */
+ {0xa4, 0x50}, /* com21 */
+ {0xa5, 0x68}, /* com26 */
+ {0xa6, 0x4a}, /* AWB green */
+ {0xa8, 0xc1}, /* refa8 */
+ {0xa9, 0xef}, /* refa9 */
+ {0xaa, 0x92},
+ {0xab, 0x04},
+ {0xac, 0x80}, /* black level control */
+ {0xad, 0x80},
+ {0xae, 0x80},
+ {0xaf, 0x80},
+ {0xb2, 0xf2},
+ {0xb3, 0x20},
+ {0xb4, 0x20}, /* ctrlb4 */
+ {0xb5, 0x00},
+ {0xb6, 0xaf},
+ {0xbb, 0xae},
+ {0xbc, 0x7f}, /* ADC channel offsets */
+ {0xdb, 0x7f},
+ {0xbe, 0x7f},
+ {0xbf, 0x7f},
+ {0xc0, 0xe2},
+ {0xc1, 0xc0},
+ {0xc2, 0x01},
+ {0xc3, 0x4e},
+ {0xc6, 0x85},
+ {0xc7, 0x80}, /* com24 */
+ {0xc9, 0xe0},
+ {0xca, 0xe8},
+ {0xcb, 0xf0},
+ {0xcc, 0xd8},
+ {0xcd, 0xf1},
+ {0x4f, 0x98},
+ {0x50, 0x98},
+ {0x51, 0x00},
+ {0x52, 0x28},
+ {0x53, 0x70},
+ {0x54, 0x98},
+ {0x58, 0x1a},
+ {0xff, 0x41}, /* read 41, write ff 00 */
+ {0x41, 0x40}, /* com16 */
+ {0xc5, 0x03}, /* 60 Hz banding filter */
+ {0x6a, 0x02}, /* 50 Hz banding filter */
+
+ {0x12, 0x62}, /* com7 - 30fps VGA YUV */
+ {0x36, 0xfa}, /* aref3 */
+ {0x69, 0x0a}, /* hv */
+ {0x8c, 0x89}, /* com22 */
+ {0x14, 0x28}, /* com9 */
+ {0x3e, 0x0c},
+ {0x41, 0x40}, /* com16 */
+ {0x72, 0x00},
+ {0x73, 0x00},
+ {0x74, 0x3a},
+ {0x75, 0x35},
+ {0x76, 0x01},
+ {0xc7, 0x80},
+ {0x03, 0x12}, /* vref */
+ {0x17, 0x16}, /* hstart */
+ {0x18, 0x02}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x3d}, /* vstop */
+ {0x32, 0xff}, /* href */
+ {0xc0, 0xaa},
+};
+
+static const u8 bridge_init_ov965x_2[][2] = {
+ {0x94, 0xaa},
+ {0xf1, 0x60},
+ {0xe5, 0x04},
+ {0xc0, 0x50},
+ {0xc1, 0x3c},
+ {0x8c, 0x00},
+ {0x8d, 0x1c},
+ {0x34, 0x05},
+
+ {0xc2, 0x0c},
+ {0xc3, 0xf9},
+ {0xda, 0x01},
+ {0x50, 0x00},
+ {0x51, 0xa0},
+ {0x52, 0x3c},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00}, /* brightness */
+ {0x57, 0x00}, /* contrast 2 */
+ {0x5c, 0x00},
+ {0x5a, 0xa0},
+ {0x5b, 0x78},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x94, 0x11},
+};
+
+static const u8 sensor_init_ov965x_2[][2] = {
+ {0x3b, 0xc4},
+ {0x1e, 0x04}, /* mvfp */
+ {0x13, 0xe0}, /* com8 */
+ {0x00, 0x00}, /* gain */
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x11, 0x03}, /* clkrc */
+ {0x6b, 0x5a}, /* dblv */
+ {0x6a, 0x05},
+ {0xc5, 0x07},
+ {0xa2, 0x4b},
+ {0xa3, 0x3e},
+ {0x2d, 0x00},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc0},
+ {0x2d, 0x00},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc1},
+ {0x3f, 0x01},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc1},
+ {0x4f, 0x98},
+ {0x50, 0x98},
+ {0x51, 0x00},
+ {0x52, 0x28},
+ {0x53, 0x70},
+ {0x54, 0x98},
+ {0x58, 0x1a},
+ {0xff, 0x41}, /* read 41, write ff 00 */
+ {0x41, 0x40}, /* com16 */
+ {0x56, 0x40},
+ {0x55, 0x8f},
+ {0x10, 0x25}, /* aech - exposure high bits */
+ {0xff, 0x13}, /* read 13, write ff 00 */
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+};
+
+static const u8 sensor_start_ov965x[][2] = {
+ {0x12, 0x62}, /* com7 - 30fps VGA YUV */
+ {0x36, 0xfa}, /* aref3 */
+ {0x69, 0x0a}, /* hv */
+ {0x8c, 0x89}, /* com22 */
+ {0x14, 0x28}, /* com9 */
+ {0x3e, 0x0c}, /* com14 */
+ {0x41, 0x40}, /* com16 */
+ {0x72, 0x00},
+ {0x73, 0x00},
+ {0x74, 0x3a},
+ {0x75, 0x35},
+ {0x76, 0x01},
+ {0xc7, 0x80}, /* com24 */
+ {0x03, 0x12}, /* vref */
+ {0x17, 0x16}, /* hstart */
+ {0x18, 0x02}, /* hstop */
+ {0x19, 0x01}, /* vstrt */
+ {0x1a, 0x3d}, /* vstop */
+ {0x32, 0xff}, /* href */
+ {0xc0, 0xaa},
+ {}
+};
+
+static const u8 bridge_start_ov965x[][2] = {
+ {0x94, 0xaa},
+ {0xf1, 0x60},
+ {0xe5, 0x04},
+ {0xc0, 0x50},
+ {0xc1, 0x3c},
+ {0x8c, 0x00},
+ {0x8d, 0x1c},
+ {0x34, 0x05},
+ {}
+};
+
+static const u8 bridge_start_ov965x_vga[][2] = {
+ {0xc2, 0x0c},
+ {0xc3, 0xf9},
+ {0xda, 0x01},
+ {0x50, 0x00},
+ {0x51, 0xa0},
+ {0x52, 0x3c},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x57, 0x00},
+ {0x5c, 0x00},
+ {0x5a, 0xa0},
+ {0x5b, 0x78},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x94, 0x11},
+ {}
+};
+
+static const u8 bridge_start_ov965x_cif[][2] = {
+ {0xc2, 0x4c},
+ {0xc3, 0xf9},
+ {0xda, 0x00},
+ {0x50, 0x00},
+ {0x51, 0xa0},
+ {0x52, 0x78},
+ {0x53, 0x00},
+ {0x54, 0x00},
+ {0x55, 0x00},
+ {0x57, 0x00},
+ {0x5c, 0x00},
+ {0x5a, 0x50},
+ {0x5b, 0x3c},
+ {0x35, 0x02},
+ {0xd9, 0x10},
+ {0x94, 0x11},
+ {}
+};
+
+static const u8 sensor_start_ov965x_vga[][2] = {
+ {0x3b, 0xc4}, /* com11 - night mode 1/4 frame rate */
+ {0x1e, 0x04}, /* mvfp */
+ {0x13, 0xe0}, /* com8 */
+ {0x00, 0x00},
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x11, 0x03}, /* clkrc */
+ {0x6b, 0x5a}, /* dblv */
+ {0x6a, 0x05}, /* 50 Hz banding filter */
+ {0xc5, 0x07}, /* 60 Hz banding filter */
+ {0xa2, 0x4b}, /* bd50 */
+ {0xa3, 0x3e}, /* bd60 */
+
+ {0x2d, 0x00}, /* advfl */
+ {}
+};
+
+static const u8 sensor_start_ov965x_cif[][2] = {
+ {0x3b, 0xe4}, /* com11 - night mode 1/4 frame rate */
+ {0x1e, 0x04}, /* mvfp */
+ {0x13, 0xe0}, /* com8 */
+ {0x00, 0x00},
+ {0x13, 0xe7}, /* com8 - everything (AGC, AWB and AEC) */
+ {0x11, 0x01}, /* clkrc */
+ {0x6b, 0x5a}, /* dblv */
+ {0x6a, 0x02}, /* 50 Hz banding filter */
+ {0xc5, 0x03}, /* 60 Hz banding filter */
+ {0xa2, 0x96}, /* bd50 */
+ {0xa3, 0x7d}, /* bd60 */
+
+ {0xff, 0x13}, /* read 13, write ff 00 */
+ {0x13, 0xe7},
+ {0x3a, 0x80}, /* tslb - yuyv */
+ {}
+};
+
+static const u8 sensor_start_ov965x_2[][2] = {
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc1}, /* com17 - 50 Hz filter */
+ {}
+};
+
+#if 0
+static const u8 sensor_start_ov965x_3[][2] = {
+ {0xff, 0x13}, /* read 13, write ff 00 */
+ {0x13, 0xe7},
+ {0x3a, 0x80},
+ {0xff, 0x42}, /* read 42, write ff 00 */
+ {0x42, 0xc1},
+ {}
+};
+#endif
+
+static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int ret;
+
+ 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),
+ 0x01,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
+ if (ret < 0)
+ PDEBUG(D_ERR, "write failed");
+}
+
+static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int ret;
+
+ ret = usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ 0x01,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x00, 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 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 gspca_dev *gspca_dev, int status)
+{
+ u8 data;
+
+ PDEBUG(D_CONF, "led status: %d", status);
+
+ data = ov534_reg_read(gspca_dev, 0x21);
+ data |= 0x80;
+ ov534_reg_write(gspca_dev, 0x21, data);
+
+ data = ov534_reg_read(gspca_dev, 0x23);
+ if (status)
+ data |= 0x80;
+ else
+ data &= ~0x80;
+
+ ov534_reg_write(gspca_dev, 0x23, data);
+
+ if (!status) {
+ data = ov534_reg_read(gspca_dev, 0x21);
+ data &= ~0x80;
+ ov534_reg_write(gspca_dev, 0x21, data);
+ }
+}
+
+static int sccb_check_status(struct gspca_dev *gspca_dev)
+{
+ u8 data;
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ data = ov534_reg_read(gspca_dev, OV534_REG_STATUS);
+
+ switch (data) {
+ case 0x00:
+ return 1;
+ case 0x04:
+ return 0;
+ case 0x03:
+ break;
+ default:
+ PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5",
+ data, i + 1);
+ }
+ }
+ return 0;
+}
+
+static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+{
+ PDEBUG(D_USBO, "reg: 0x%02x, 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(gspca_dev))
+ PDEBUG(D_ERR, "sccb_reg_write failed");
+}
+
+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);
+}
+
+/* output a bridge sequence (reg - val) */
+static void reg_w_array(struct gspca_dev *gspca_dev,
+ const u8 (*data)[2], int len)
+{
+ while (--len >= 0) {
+ ov534_reg_write(gspca_dev, (*data)[0], (*data)[1]);
+ data++;
+ }
+}
+
+/* output a sensor sequence (reg - val) */
+static void sccb_w_array(struct gspca_dev *gspca_dev,
+ const u8 (*data)[2], int len)
+{
+ while (--len >= 0) {
+ if ((*data)[0] != 0xff) {
+ sccb_reg_write(gspca_dev, (*data)[0], (*data)[1]);
+ } else {
+ sccb_reg_read(gspca_dev, (*data)[1]);
+ sccb_reg_write(gspca_dev, 0xff, 0x00);
+ }
+ data++;
+ }
+}
+
/* set framerate */
static void ov534_set_frame_rate(struct gspca_dev *gspca_dev)
{
@@ -346,44 +798,28 @@ static void ov534_set_frame_rate(struct gspca_dev *gspca_dev)
PDEBUG(D_PROBE, "frame_rate: %d", fr);
}
-/* setup method */
-static void ov534_setup(struct gspca_dev *gspca_dev)
-{
- 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 */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
+ struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
+ sd->sensor = id->driver_info;
+
cam = &gspca_dev->cam;
- cam->cam_mode = vga_mode;
- cam->nmodes = ARRAY_SIZE(vga_mode);
+ if (sd->sensor == SENSOR_OV772X) {
+ cam->cam_mode = vga_yuyv_mode;
+ cam->nmodes = ARRAY_SIZE(vga_yuyv_mode);
- cam->bulk_size = 16384;
- cam->bulk_nurbs = 2;
+ cam->bulk = 1;
+ cam->bulk_size = 16384;
+ cam->bulk_nurbs = 2;
+ } else { /* ov965x */
+ cam->cam_mode = vga_jpeg_mode;
+ cam->nmodes = ARRAY_SIZE(vga_jpeg_mode);
+ }
return 0;
}
@@ -391,26 +827,118 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
- ov534_setup(gspca_dev);
- ov534_set_frame_rate(gspca_dev);
+ struct sd *sd = (struct sd *) gspca_dev;
+ u16 sensor_id;
+ static const u8 sensor_addr[2] = {
+ 0x42, /* 0 SENSOR_OV772X */
+ 0x60, /* 1 SENSOR_OV965X */
+ };
+
+ /* reset bridge */
+ ov534_reg_write(gspca_dev, 0xe7, 0x3a);
+ ov534_reg_write(gspca_dev, 0xe0, 0x08);
+ msleep(100);
+
+ /* initialize the sensor address */
+ ov534_reg_write(gspca_dev, OV534_REG_ADDRESS,
+ sensor_addr[sd->sensor]);
+
+ /* reset sensor */
+ sccb_reg_write(gspca_dev, 0x12, 0x80);
+ msleep(10);
+
+ /* probe the sensor */
+ sccb_reg_read(gspca_dev, 0x0a);
+ sensor_id = sccb_reg_read(gspca_dev, 0x0a) << 8;
+ sccb_reg_read(gspca_dev, 0x0b);
+ sensor_id |= sccb_reg_read(gspca_dev, 0x0b);
+ PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id);
+
+ /* initialize */
+ switch (sd->sensor) {
+ case SENSOR_OV772X:
+ reg_w_array(gspca_dev, bridge_init_ov722x,
+ ARRAY_SIZE(bridge_init_ov722x));
+ ov534_set_led(gspca_dev, 1);
+ sccb_w_array(gspca_dev, sensor_init_ov722x,
+ ARRAY_SIZE(sensor_init_ov722x));
+ ov534_reg_write(gspca_dev, 0xe0, 0x09);
+ ov534_set_led(gspca_dev, 0);
+ ov534_set_frame_rate(gspca_dev);
+ break;
+ default:
+/* case SENSOR_OV965X: */
+ reg_w_array(gspca_dev, bridge_init_ov965x,
+ ARRAY_SIZE(bridge_init_ov965x));
+ sccb_w_array(gspca_dev, sensor_init_ov965x,
+ ARRAY_SIZE(sensor_init_ov965x));
+ reg_w_array(gspca_dev, bridge_init_ov965x_2,
+ ARRAY_SIZE(bridge_init_ov965x_2));
+ sccb_w_array(gspca_dev, sensor_init_ov965x_2,
+ ARRAY_SIZE(sensor_init_ov965x_2));
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ ov534_reg_write(gspca_dev, 0xe0, 0x01);
+ ov534_set_led(gspca_dev, 0);
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ }
return 0;
}
static int sd_start(struct gspca_dev *gspca_dev)
{
- /* start streaming data */
- ov534_set_led(gspca_dev, 1);
- ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ struct sd *sd = (struct sd *) gspca_dev;
+ int mode;
+ switch (sd->sensor) {
+ case SENSOR_OV772X:
+ ov534_set_led(gspca_dev, 1);
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ break;
+ default:
+/* case SENSOR_OV965X: */
+
+ sccb_w_array(gspca_dev, sensor_start_ov965x,
+ ARRAY_SIZE(sensor_start_ov965x));
+ reg_w_array(gspca_dev, bridge_start_ov965x,
+ ARRAY_SIZE(bridge_start_ov965x));
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ if (mode != 0) { /* 320x240 */
+ reg_w_array(gspca_dev, bridge_start_ov965x_cif,
+ ARRAY_SIZE(bridge_start_ov965x_cif));
+ sccb_w_array(gspca_dev, sensor_start_ov965x_cif,
+ ARRAY_SIZE(sensor_start_ov965x_cif));
+ } else { /* 640x480 */
+ reg_w_array(gspca_dev, bridge_start_ov965x_vga,
+ ARRAY_SIZE(bridge_start_ov965x_vga));
+ sccb_w_array(gspca_dev, sensor_start_ov965x_vga,
+ ARRAY_SIZE(sensor_start_ov965x_vga));
+ }
+ sccb_w_array(gspca_dev, sensor_start_ov965x_2,
+ ARRAY_SIZE(sensor_start_ov965x_2));
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ ov534_set_led(gspca_dev, 1);
+ }
return 0;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
- /* stop streaming data */
- ov534_reg_write(gspca_dev, 0xe0, 0x09);
- ov534_set_led(gspca_dev, 0);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->sensor) {
+ case SENSOR_OV772X:
+ ov534_reg_write(gspca_dev, 0xe0, 0x09);
+ ov534_set_led(gspca_dev, 0);
+ break;
+ default:
+/* case SENSOR_OV965X: */
+ ov534_reg_write(gspca_dev, 0xe0, 0x01);
+ ov534_set_led(gspca_dev, 0);
+ ov534_reg_write(gspca_dev, 0xe0, 0x00);
+ break;
+ }
}
/* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */
@@ -428,75 +956,80 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, struct gspca_frame *frame,
{
struct sd *sd = (struct sd *) gspca_dev;
__u32 this_pts;
- int this_fid;
+ u16 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;
- }
+ do {
+ len = min(remaining_len, 2040); /*fixme: was 2048*/
- /* Check errors */
- if (data[1] & UVC_STREAM_ERR) {
- PDEBUG(D_PACK, "payload error");
- goto discard;
- }
+ /* 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. */
- /* 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);
+ /* Verify UVC header. Header length is always 12 */
+ if (data[0] != 12 || len < 12) {
+ PDEBUG(D_PACK, "bad header");
+ goto discard;
+ }
- /* If this packet is marked as EOF, end the frame */
- if (data[1] & UVC_STREAM_EOF) {
- sd->last_pts = 0;
+ /* Check errors */
+ if (data[1] & UVC_STREAM_ERR) {
+ PDEBUG(D_PACK, "payload error");
+ goto discard;
+ }
- if ((frame->data_end - frame->data) !=
- (gspca_dev->width * gspca_dev->height * 2)) {
- PDEBUG(D_PACK, "short frame");
+ /* 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) {
+ if (gspca_dev->last_packet_type == INTER_PACKET)
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET, frame,
+ NULL, 0);
+ sd->last_pts = this_pts;
+ sd->last_fid = this_fid;
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ data + 12, len - 12);
+ /* If this packet is marked as EOF, end the frame */
+ } else if (data[1] & UVC_STREAM_EOF) {
+ sd->last_pts = 0;
+#if 0
+/*fixme: check if not jpeg*/
+ if (frame->data_end - frame->data !=
+ gspca_dev->width * gspca_dev->height * 2) {
+ PDEBUG(D_PACK, "short frame");
+ goto discard;
+ }
+#endif
+ frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
+ data + 12, len - 12);
+ } else {
+
+ /* Add the data from this payload */
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data + 12, len - 12);
+ }
- gspca_frame_add(gspca_dev, LAST_PACKET, frame, NULL, 0);
- }
- /* Done this payload */
- goto scan_next;
+ /* 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;
+ /* Discard data until a new frame starts. */
+ gspca_frame_add(gspca_dev, DISCARD_PACKET, frame, NULL, 0);
+
+scan_next:
+ remaining_len -= len;
+ data += len;
+ } while (remaining_len > 0);
}
/* get stream parameters (framerate) */
@@ -556,11 +1089,11 @@ static const struct sd_desc sd_desc = {
/* -- module initialisation -- */
static const __devinitdata struct usb_device_id device_table[] = {
#if 0
- /* these two are not supported yet, different sensors */
- {USB_DEVICE(0x06f8, 0x3002)}, /* Hercules Blog Webcam */
- {USB_DEVICE(0x06f8, 0x3003)}, /* Hercules Dualpix HD Weblog */
+ /* not supported yet */
+ {USB_DEVICE(0x06f8, 0x3002), .driver_info = SENSOR_unknown},
#endif
- {USB_DEVICE(0x1415, 0x2000)}, /* Sony HD Eye for PS3 (SLEH 00201) */
+ {USB_DEVICE(0x06f8, 0x3003), .driver_info = SENSOR_OV965X},
+ {USB_DEVICE(0x1415, 0x2000), .driver_info = SENSOR_OV772X},
{}
};
diff --git a/linux/drivers/media/video/gspca/sonixb.c b/linux/drivers/media/video/gspca/sonixb.c
index edb2bfa85..4141cf494 100644
--- a/linux/drivers/media/video/gspca/sonixb.c
+++ b/linux/drivers/media/video/gspca/sonixb.c
@@ -907,6 +907,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = sif_mode;
cam->nmodes = ARRAY_SIZE(sif_mode);
}
+ cam->npkt = 36; /* 36 packets per ISOC message */
+
sd->brightness = BRIGHTNESS_DEF;
sd->gain = GAIN_DEF;
sd->exposure = EXPOSURE_DEF;
diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c
index 36d6f50be..a4c935d69 100644
--- a/linux/drivers/media/video/gspca/sonixj.c
+++ b/linux/drivers/media/video/gspca/sonixj.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "sonixj"
#include "gspca.h"
-#define QUANT_VAL 4 /* quantization table */
#include "jpeg.h"
#define V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0)
@@ -47,6 +46,13 @@ struct sd {
u8 gamma;
u8 vflip; /* ov7630/ov7648 only */
u8 infrared; /* mt9v111 only */
+ u8 quality; /* image quality */
+#define QUALITY_MIN 60
+#define QUALITY_MAX 95
+#define QUALITY_DEF 80
+ u8 jpegqual; /* webcam quality */
+
+ u8 reg18;
s8 ag_cnt;
#define AG_CNT_START 13
@@ -56,7 +62,6 @@ struct sd {
#define BRIDGE_SN9C105 1
#define BRIDGE_SN9C110 2
#define BRIDGE_SN9C120 3
-#define BRIDGE_SN9C325 4
u8 sensor; /* Type of image sensor chip */
#define SENSOR_HV7131R 0
#define SENSOR_MI0360 1
@@ -68,6 +73,8 @@ struct sd {
#define SENSOR_OV7660 7
#define SENSOR_SP80708 8
u8 i2c_base;
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -350,9 +357,9 @@ static const u8 sn_ov7648[0x1c] = {
static const u8 sn_ov7660[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
- 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20,
+ 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00,
/* reg8 reg9 rega regb regc regd rege regf */
- 0x81, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
0x03, 0x00, 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20,
/* reg18 reg19 reg1a reg1b */
@@ -757,6 +764,7 @@ static const u8 ov7660_sensor_init[][8] = {
{0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
{0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
{0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */
+ {0xb1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10},
/****** (some exchanges in the win trace) ******/
{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */
/* bits[3..0]reserved */
@@ -867,25 +875,6 @@ static const u8 sp80708_sensor_init[][8] = {
{}
};
-static const u8 qtable4[] = {
- 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06,
- 0x06, 0x06, 0x08, 0x06, 0x06, 0x08, 0x0a, 0x11,
- 0x0a, 0x0a, 0x08, 0x08, 0x0a, 0x15, 0x0f, 0x0f,
- 0x0c, 0x11, 0x19, 0x15, 0x19, 0x19, 0x17, 0x15,
- 0x17, 0x17, 0x1b, 0x1d, 0x25, 0x21, 0x1b, 0x1d,
- 0x23, 0x1d, 0x17, 0x17, 0x21, 0x2e, 0x21, 0x23,
- 0x27, 0x29, 0x2c, 0x2c, 0x2c, 0x19, 0x1f, 0x30,
- 0x32, 0x2e, 0x29, 0x32, 0x25, 0x29, 0x2c, 0x29,
- 0x06, 0x08, 0x08, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
- 0x0a, 0x13, 0x29, 0x1b, 0x17, 0x1b, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29
-};
-
/* read <len> bytes to gspca_dev->usb_buf */
static void reg_r(struct gspca_dev *gspca_dev,
u16 value, int len)
@@ -1084,9 +1073,13 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
const u8 *reg9a;
static const u8 reg9a_def[] =
- {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
- static const u8 reg9a_sn9c325[] =
- {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
+#if 1
+ {0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
+#else
+ {0x00, 0x40, 0x20, 0x10, 0x00, 0x04};
+#endif
+ static const u8 reg9a_spec[] =
+ {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
static const u8 regd4[] = {0x60, 0x00, 0x00};
reg_w1(gspca_dev, 0xf1, 0x00);
@@ -1100,9 +1093,10 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); /* jfm len was 3 */
- switch (sd->bridge) {
- case BRIDGE_SN9C325:
- reg9a = reg9a_sn9c325;
+ switch (sd->sensor) {
+ case SENSOR_OV7660:
+ case SENSOR_SP80708:
+ reg9a = reg9a_spec;
break;
default:
reg9a = reg9a_def;
@@ -1127,32 +1121,24 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
reg_w1(gspca_dev, 0x17, 0x64);
reg_w1(gspca_dev, 0x01, 0x42);
break;
-#if 1
-/*jfm: from win trace */
case SENSOR_OV7630:
reg_w1(gspca_dev, 0x01, 0x61);
reg_w1(gspca_dev, 0x17, 0xe2);
reg_w1(gspca_dev, 0x01, 0x60);
reg_w1(gspca_dev, 0x01, 0x40);
break;
-#endif
case SENSOR_OV7648:
reg_w1(gspca_dev, 0x01, 0x63);
reg_w1(gspca_dev, 0x17, 0x20);
+ reg_w1(gspca_dev, 0x01, 0x62);
reg_w1(gspca_dev, 0x01, 0x42);
break;
-#if 1
-/*jfm: from win trace */
case SENSOR_OV7660:
- if (sd->bridge == BRIDGE_SN9C120) {
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- }
- /* fall thru */
-#endif
+ reg_w1(gspca_dev, 0x01, 0x61);
+ reg_w1(gspca_dev, 0x17, 0x20);
+ reg_w1(gspca_dev, 0x01, 0x60);
+ reg_w1(gspca_dev, 0x01, 0x40);
+ break;
case SENSOR_SP80708:
reg_w1(gspca_dev, 0x01, 0x63);
reg_w1(gspca_dev, 0x17, 0x20);
@@ -1161,6 +1147,9 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
mdelay(100);
reg_w1(gspca_dev, 0x02, 0x62);
break;
+/* case SENSOR_HV7131R: */
+/* case SENSOR_MI0360: */
+/* case SENSOR_MO4000: */
default:
reg_w1(gspca_dev, 0x01, 0x43);
reg_w1(gspca_dev, 0x17, 0x61);
@@ -1307,6 +1296,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
+ cam->npkt = 24; /* 24 packets per ISOC message */
sd->bridge = id->driver_info >> 16;
sd->sensor = id->driver_info >> 8;
@@ -1325,6 +1315,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
else
sd->vflip = 1;
sd->infrared = INFRARED_DEF;
+ sd->quality = QUALITY_DEF;
+ sd->jpegqual = 80;
gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
return 0;
@@ -1642,12 +1634,49 @@ static void setinfrared(struct sd *sd)
#endif
}
+static void setjpegqual(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, sc;
+
+ if (sd->jpegqual < 50)
+ sc = 5000 / sd->jpegqual;
+ else
+ sc = 200 - sd->jpegqual * 2;
+#if USB_BUF_SZ < 64
+#error "No room enough in usb_buf for quantization table"
+#endif
+ for (i = 0; i < 64; i++)
+ gspca_dev->usb_buf[i] =
+ (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0x0100, 0,
+ gspca_dev->usb_buf, 64,
+ 500);
+ for (i = 0; i < 64; i++)
+ gspca_dev->usb_buf[i] =
+ (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0x0140, 0,
+ gspca_dev->usb_buf, 64,
+ 500);
+
+ sd->reg18 ^= 0x40;
+ reg_w1(gspca_dev, 0x18, sd->reg18);
+}
+
/* -- start the camera -- */
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
- u8 reg1, reg17, reg18;
+ u8 reg1, reg17;
const u8 *sn9c1xx;
int mode;
static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
@@ -1656,6 +1685,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
static const u8 CE_ov76xx[] =
{ 0x32, 0xdd, 0x32, 0xdd };
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x21); /* JPEG 422 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
sn9c1xx = sn_tb[(int) sd->sensor];
configure_gpio(gspca_dev, sn9c1xx);
@@ -1681,15 +1716,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_OV7648:
reg17 = 0x20;
break;
-#if 1
-/*jfm: from win trace */
case SENSOR_OV7660:
- if (sd->bridge == BRIDGE_SN9C120) {
- reg17 = 0xa0;
- break;
- }
- /* fall thru */
-#endif
+ reg17 = 0xa0;
+ break;
default:
reg17 = 0x60;
break;
@@ -1714,16 +1743,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x9a, 0x0a);
reg_w1(gspca_dev, 0x99, 0x60);
break;
+ case SENSOR_OV7660:
+ reg_w1(gspca_dev, 0x9a, 0x05);
+ if (sd->bridge == BRIDGE_SN9C105)
+ reg_w1(gspca_dev, 0x99, 0xff);
+ else
+ reg_w1(gspca_dev, 0x99, 0x5b);
+ break;
case SENSOR_SP80708:
reg_w1(gspca_dev, 0x9a, 0x05);
reg_w1(gspca_dev, 0x99, 0x59);
break;
- case SENSOR_OV7660:
- if (sd->bridge == BRIDGE_SN9C120) {
- reg_w1(gspca_dev, 0x9a, 0x05);
- break;
- }
- /* fall thru */
default:
reg_w1(gspca_dev, 0x9a, 0x08);
reg_w1(gspca_dev, 0x99, 0x59);
@@ -1816,13 +1846,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
/* here change size mode 0 -> VGA; 1 -> CIF */
- reg18 = sn9c1xx[0x18] | (mode << 4);
- reg_w1(gspca_dev, 0x18, reg18 | 0x40);
-
- reg_w(gspca_dev, 0x0100, qtable4, 0x40);
- reg_w(gspca_dev, 0x0140, qtable4 + 0x40, 0x40);
-
- reg_w1(gspca_dev, 0x18, reg18);
+ sd->reg18 = sn9c1xx[0x18] | (mode << 4) | 0x40;
+ reg_w1(gspca_dev, 0x18, sd->reg18);
+ setjpegqual(gspca_dev);
reg_w1(gspca_dev, 0x17, reg17);
reg_w1(gspca_dev, 0x01, reg1);
@@ -1884,6 +1910,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0xf1, 0x00);
}
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ kfree(sd->jpeg_hdr);
+}
+
static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1967,7 +2000,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
if (gspca_dev->last_packet_type == LAST_PACKET) {
/* put the JPEG 422 header */
- jpeg_put_header(gspca_dev, frame, 0x21);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
}
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
@@ -2134,6 +2168,34 @@ static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -2143,8 +2205,11 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
@@ -2159,12 +2224,11 @@ static const __devinitdata struct usb_device_id device_table[] = {
#endif
{USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
{USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)},
-#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(0x06f8, 0x3008), BSI(SN9C105, OV7660, 0x21)},
{USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)},
/* bw600.inf:
{USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */
@@ -2183,7 +2247,12 @@ static const __devinitdata struct usb_device_id device_table[] = {
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
#endif
+ {USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/
/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
+ {USB_DEVICE(0x0c45, 0x610a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c128*/
+ {USB_DEVICE(0x0c45, 0x610b), BSI(SN9C120, OV7660, 0x21)}, /*sn9c128*/
+ {USB_DEVICE(0x0c45, 0x610c), BSI(SN9C120, HV7131R, 0x11)}, /*sn9c128*/
+ {USB_DEVICE(0x0c45, 0x610e), BSI(SN9C120, OV7630, 0x21)}, /*sn9c128*/
/* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
{USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/
diff --git a/linux/drivers/media/video/gspca/spca500.c b/linux/drivers/media/video/gspca/spca500.c
index 94caba63b..9717da6af 100644
--- a/linux/drivers/media/video/gspca/spca500.c
+++ b/linux/drivers/media/video/gspca/spca500.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "spca500"
#include "gspca.h"
-#define QUANT_VAL 5 /* quantization table */
#include "jpeg.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
@@ -33,12 +32,13 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u8 packet[ISO_MAX_SIZE + 128];
- /* !! no more than 128 ff in an ISO packet */
-
unsigned char brightness;
unsigned char contrast;
unsigned char colors;
+ u8 quality;
+#define QUALITY_MIN 70
+#define QUALITY_MAX 95
+#define QUALITY_DEF 85
char subtype;
#define AgfaCl20 0
@@ -56,6 +56,8 @@ struct sd {
#define Optimedia 12
#define PalmPixDC85 13
#define ToptroIndus 14
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -657,6 +659,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
+ sd->quality = QUALITY_DEF;
return 0;
}
@@ -682,6 +685,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
__u8 Data;
__u8 xmult, ymult;
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x22); /* JPEG 411 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
if (sd->subtype == LogitechClickSmart310) {
xmult = 0x16;
ymult = 0x12;
@@ -897,6 +906,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
gspca_dev->usb_buf[0]);
}
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ kfree(sd->jpeg_hdr);
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -904,7 +920,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
- __u8 *s, *d;
static __u8 ffd9[] = {0xff, 0xd9};
/* frames are jpeg 4.1.1 without 0xff escape */
@@ -917,7 +932,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
ffd9, 2);
/* put the JPEG header in the new frame */
- jpeg_put_header(gspca_dev, frame, 0x22);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
data += SPCA500_OFFSET_DATA;
len -= SPCA500_OFFSET_DATA;
@@ -927,22 +943,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
}
/* add 0x00 after 0xff */
- for (i = len; --i >= 0; )
- if (data[i] == 0xff)
- break;
- if (i < 0) { /* no 0xff */
- gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
- return;
- }
- s = data;
- d = sd->packet;
- for (i = 0; i < len; i++) {
- *d++ = *s++;
- if (s[-1] == 0xff)
- *d++ = 0x00;
- }
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- sd->packet, d - sd->packet);
+ i = 0;
+ do {
+ if (data[i] == 0xff) {
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data, i + 1);
+ len -= i;
+ data += i;
+ *data = 0x00;
+ i = 0;
+ }
+ i++;
+ } while (i < len);
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
static void setbrightness(struct gspca_dev *gspca_dev)
@@ -1021,6 +1034,34 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -1030,7 +1071,10 @@ static struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
diff --git a/linux/drivers/media/video/gspca/spca508.c b/linux/drivers/media/video/gspca/spca508.c
index e3afc9e7f..7fd8079c2 100644
--- a/linux/drivers/media/video/gspca/spca508.c
+++ b/linux/drivers/media/video/gspca/spca508.c
@@ -1,7 +1,7 @@
/*
* SPCA508 chip based cameras subdriver
*
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009 Jean-Francois Moine <http://moinejf.free.fr>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,9 +30,9 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- unsigned char brightness;
+ u8 brightness;
- char subtype;
+ u8 subtype;
#define CreativeVista 0
#define HamaUSBSightcam 1
#define HamaUSBSightcam2 2
@@ -86,58 +86,54 @@ static const struct v4l2_pix_format sif_mode[] = {
};
/* Frame packet header offsets for the spca508 */
+#if 0
+#define SPCA508_OFFSET_
#define SPCA508_OFFSET_TYPE 1
+#define SPCA508_IMAGE_TYPE_MASK 0x1f
+#define SPCA508_SNAPBIT 0x20
+#define SPCA508_SNAPCTRL 0x40
#define SPCA508_OFFSET_COMPRESS 2
#define SPCA508_OFFSET_FRAMSEQ 8
+#define SPCA508_OFFSET_GPIO 9
+#define SPCA508_OFFSET_GLBINF 10
#define SPCA508_OFFSET_WIN1LUM 11
+#define SPCA508_OFFSET_WIN2LUM 12
+#define SPCA508_OFFSET_WIN1RG 13
+#define SPCA508_OFFSET_WIN1BG 14
+#define SPCA508_OFFSET_WIN2RG 15
+#define SPCA508_OFFSET_WIN2BG 16
+#define SPCA508_OFFSET_21 21
+#define SPCA508_GAMMAEN 0x01
+#define SPCA508_EDGEMODE 0x02
+#endif
#define SPCA508_OFFSET_DATA 37
-#define SPCA508_SNAPBIT 0x20
-#define SPCA508_SNAPCTRL 0x40
-/*************** I2c ****************/
-#define SPCA508_INDEX_I2C_BASE 0x8800
-
/*
* Initialization data: this is the first set-up data written to the
* device (before the open data).
*/
static const u16 spca508_init_data[][2] =
{
- /* line URB value, index */
- /* 44274 1804 */ {0x0000, 0x870b},
-
- /* 44299 1805 */ {0x0020, 0x8112},
- /* Video drop enable, ISO streaming disable */
- /* 44324 1806 */ {0x0003, 0x8111},
- /* Reset compression & memory */
- /* 44349 1807 */ {0x0000, 0x8110},
- /* Disable all outputs */
- /* 44372 1808 */ /* READ {0x0000, 0x8114} -> 0000: 00 */
- /* 44398 1809 */ {0x0000, 0x8114},
- /* SW GPIO data */
- /* 44423 1810 */ {0x0008, 0x8110},
- /* Enable charge pump output */
- /* 44527 1811 */ {0x0002, 0x8116},
- /* 200 kHz pump clock */
- /* 44555 1812 */
- /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
- /* 44590 1813 */ {0x0003, 0x8111},
- /* Reset compression & memory */
- /* 44615 1814 */ {0x0000, 0x8111},
- /* Normal mode (not reset) */
- /* 44640 1815 */ {0x0098, 0x8110},
- /* Enable charge pump output, sync.serial,external 2x clock */
- /* 44665 1816 */ {0x000d, 0x8114},
- /* SW GPIO data */
- /* 44690 1817 */ {0x0002, 0x8116},
- /* 200 kHz pump clock */
- /* 44715 1818 */ {0x0020, 0x8112},
- /* Video drop enable, ISO streaming disable */
+ {0x0000, 0x870b},
+
+ {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */
+ {0x0003, 0x8111}, /* Reset compression & memory */
+ {0x0000, 0x8110}, /* Disable all outputs */
+ /* READ {0x0000, 0x8114} -> 0000: 00 */
+ {0x0000, 0x8114}, /* SW GPIO data */
+ {0x0008, 0x8110}, /* Enable charge pump output */
+ {0x0002, 0x8116}, /* 200 kHz pump clock */
+ /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE:) */
+ {0x0003, 0x8111}, /* Reset compression & memory */
+ {0x0000, 0x8111}, /* Normal mode (not reset) */
+ {0x0098, 0x8110},
+ /* Enable charge pump output, sync.serial,external 2x clock */
+ {0x000d, 0x8114}, /* SW GPIO data */
+ {0x0002, 0x8116}, /* 200 kHz pump clock */
+ {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */
/* --------------------------------------- */
- /* 44740 1819 */ {0x000f, 0x8402},
- /* memory bank */
- /* 44765 1820 */ {0x0000, 0x8403},
- /* ... address */
+ {0x000f, 0x8402}, /* memory bank */
+ {0x0000, 0x8403}, /* ... address */
/* --------------------------------------- */
/* 0x88__ is Synchronous Serial Interface. */
/* TBD: This table could be expressed more compactly */
@@ -145,342 +141,307 @@ static const u16 spca508_init_data[][2] =
/* TBD: Should see if the values in spca50x_i2c_data */
/* would work with the VQ110 instead of the values */
/* below. */
- /* 44790 1821 */ {0x00c0, 0x8804},
- /* SSI slave addr */
- /* 44815 1822 */ {0x0008, 0x8802},
- /* 375 Khz SSI clock */
- /* 44838 1823 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 44862 1824 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 44888 1825 */ {0x0008, 0x8802},
- /* 375 Khz SSI clock */
- /* 44913 1826 */ {0x0012, 0x8801},
- /* SSI reg addr */
- /* 44938 1827 */ {0x0080, 0x8800},
- /* SSI data to write */
- /* 44961 1828 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 44985 1829 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45009 1830 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 45035 1831 */ {0x0008, 0x8802},
- /* 375 Khz SSI clock */
- /* 45060 1832 */ {0x0012, 0x8801},
- /* SSI reg addr */
- /* 45085 1833 */ {0x0000, 0x8800},
- /* SSI data to write */
- /* 45108 1834 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45132 1835 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45156 1836 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 45182 1837 */ {0x0008, 0x8802},
- /* 375 Khz SSI clock */
- /* 45207 1838 */ {0x0011, 0x8801},
- /* SSI reg addr */
- /* 45232 1839 */ {0x0040, 0x8800},
- /* SSI data to write */
- /* 45255 1840 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45279 1841 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45303 1842 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 45329 1843 */ {0x0008, 0x8802},
- /* 45354 1844 */ {0x0013, 0x8801},
- /* 45379 1845 */ {0x0000, 0x8800},
- /* 45402 1846 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45426 1847 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45450 1848 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 45476 1849 */ {0x0008, 0x8802},
- /* 45501 1850 */ {0x0014, 0x8801},
- /* 45526 1851 */ {0x0000, 0x8800},
- /* 45549 1852 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45573 1853 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45597 1854 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 45623 1855 */ {0x0008, 0x8802},
- /* 45648 1856 */ {0x0015, 0x8801},
- /* 45673 1857 */ {0x0001, 0x8800},
- /* 45696 1858 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45720 1859 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45744 1860 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 45770 1861 */ {0x0008, 0x8802},
- /* 45795 1862 */ {0x0016, 0x8801},
- /* 45820 1863 */ {0x0003, 0x8800},
- /* 45843 1864 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45867 1865 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 45891 1866 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 45917 1867 */ {0x0008, 0x8802},
- /* 45942 1868 */ {0x0017, 0x8801},
- /* 45967 1869 */ {0x0036, 0x8800},
- /* 45990 1870 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46014 1871 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46038 1872 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 46064 1873 */ {0x0008, 0x8802},
- /* 46089 1874 */ {0x0018, 0x8801},
- /* 46114 1875 */ {0x00ec, 0x8800},
- /* 46137 1876 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46161 1877 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46185 1878 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 46211 1879 */ {0x0008, 0x8802},
- /* 46236 1880 */ {0x001a, 0x8801},
- /* 46261 1881 */ {0x0094, 0x8800},
- /* 46284 1882 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46308 1883 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46332 1884 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 46358 1885 */ {0x0008, 0x8802},
- /* 46383 1886 */ {0x001b, 0x8801},
- /* 46408 1887 */ {0x0000, 0x8800},
- /* 46431 1888 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46455 1889 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46479 1890 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 46505 1891 */ {0x0008, 0x8802},
- /* 46530 1892 */ {0x0027, 0x8801},
- /* 46555 1893 */ {0x00a2, 0x8800},
- /* 46578 1894 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46602 1895 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46626 1896 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 46652 1897 */ {0x0008, 0x8802},
- /* 46677 1898 */ {0x0028, 0x8801},
- /* 46702 1899 */ {0x0040, 0x8800},
- /* 46725 1900 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46749 1901 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46773 1902 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 46799 1903 */ {0x0008, 0x8802},
- /* 46824 1904 */ {0x002a, 0x8801},
- /* 46849 1905 */ {0x0084, 0x8800},
- /* 46872 1906 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46896 1907 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 46920 1908 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 46946 1909 */ {0x0008, 0x8802},
- /* 46971 1910 */ {0x002b, 0x8801},
- /* 46996 1911 */ {0x00a8, 0x8800},
- /* 47019 1912 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47043 1913 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47067 1914 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 47093 1915 */ {0x0008, 0x8802},
- /* 47118 1916 */ {0x002c, 0x8801},
- /* 47143 1917 */ {0x00fe, 0x8800},
- /* 47166 1918 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47190 1919 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47214 1920 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 47240 1921 */ {0x0008, 0x8802},
- /* 47265 1922 */ {0x002d, 0x8801},
- /* 47290 1923 */ {0x0003, 0x8800},
- /* 47313 1924 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47337 1925 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47361 1926 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 47387 1927 */ {0x0008, 0x8802},
- /* 47412 1928 */ {0x0038, 0x8801},
- /* 47437 1929 */ {0x0083, 0x8800},
- /* 47460 1930 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47484 1931 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47508 1932 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 47534 1933 */ {0x0008, 0x8802},
- /* 47559 1934 */ {0x0033, 0x8801},
- /* 47584 1935 */ {0x0081, 0x8800},
- /* 47607 1936 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47631 1937 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47655 1938 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 47681 1939 */ {0x0008, 0x8802},
- /* 47706 1940 */ {0x0034, 0x8801},
- /* 47731 1941 */ {0x004a, 0x8800},
- /* 47754 1942 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47778 1943 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47802 1944 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 47828 1945 */ {0x0008, 0x8802},
- /* 47853 1946 */ {0x0039, 0x8801},
- /* 47878 1947 */ {0x0000, 0x8800},
- /* 47901 1948 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47925 1949 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 47949 1950 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 47975 1951 */ {0x0008, 0x8802},
- /* 48000 1952 */ {0x0010, 0x8801},
- /* 48025 1953 */ {0x00a8, 0x8800},
- /* 48048 1954 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48072 1955 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48096 1956 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 48122 1957 */ {0x0008, 0x8802},
- /* 48147 1958 */ {0x0006, 0x8801},
- /* 48172 1959 */ {0x0058, 0x8800},
- /* 48195 1960 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48219 1961 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48243 1962 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 48269 1963 */ {0x0008, 0x8802},
- /* 48294 1964 */ {0x0000, 0x8801},
- /* 48319 1965 */ {0x0004, 0x8800},
- /* 48342 1966 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48366 1967 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48390 1968 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 48416 1969 */ {0x0008, 0x8802},
- /* 48441 1970 */ {0x0040, 0x8801},
- /* 48466 1971 */ {0x0080, 0x8800},
- /* 48489 1972 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48513 1973 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48537 1974 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 48563 1975 */ {0x0008, 0x8802},
- /* 48588 1976 */ {0x0041, 0x8801},
- /* 48613 1977 */ {0x000c, 0x8800},
- /* 48636 1978 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48660 1979 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48684 1980 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 48710 1981 */ {0x0008, 0x8802},
- /* 48735 1982 */ {0x0042, 0x8801},
- /* 48760 1983 */ {0x000c, 0x8800},
- /* 48783 1984 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48807 1985 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48831 1986 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 48857 1987 */ {0x0008, 0x8802},
- /* 48882 1988 */ {0x0043, 0x8801},
- /* 48907 1989 */ {0x0028, 0x8800},
- /* 48930 1990 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48954 1991 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 48978 1992 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 49004 1993 */ {0x0008, 0x8802},
- /* 49029 1994 */ {0x0044, 0x8801},
- /* 49054 1995 */ {0x0080, 0x8800},
- /* 49077 1996 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49101 1997 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49125 1998 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 49151 1999 */ {0x0008, 0x8802},
- /* 49176 2000 */ {0x0045, 0x8801},
- /* 49201 2001 */ {0x0020, 0x8800},
- /* 49224 2002 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49248 2003 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49272 2004 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 49298 2005 */ {0x0008, 0x8802},
- /* 49323 2006 */ {0x0046, 0x8801},
- /* 49348 2007 */ {0x0020, 0x8800},
- /* 49371 2008 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49395 2009 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49419 2010 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 49445 2011 */ {0x0008, 0x8802},
- /* 49470 2012 */ {0x0047, 0x8801},
- /* 49495 2013 */ {0x0080, 0x8800},
- /* 49518 2014 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49542 2015 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49566 2016 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 49592 2017 */ {0x0008, 0x8802},
- /* 49617 2018 */ {0x0048, 0x8801},
- /* 49642 2019 */ {0x004c, 0x8800},
- /* 49665 2020 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49689 2021 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49713 2022 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 49739 2023 */ {0x0008, 0x8802},
- /* 49764 2024 */ {0x0049, 0x8801},
- /* 49789 2025 */ {0x0084, 0x8800},
- /* 49812 2026 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49836 2027 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49860 2028 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 49886 2029 */ {0x0008, 0x8802},
- /* 49911 2030 */ {0x004a, 0x8801},
- /* 49936 2031 */ {0x0084, 0x8800},
- /* 49959 2032 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 49983 2033 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 50007 2034 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 50033 2035 */ {0x0008, 0x8802},
- /* 50058 2036 */ {0x004b, 0x8801},
- /* 50083 2037 */ {0x0084, 0x8800},
- /* 50106 2038 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ {0x00c0, 0x8804}, /* SSI slave addr */
+ {0x0008, 0x8802}, /* 375 Khz SSI clock */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802}, /* 375 Khz SSI clock */
+ {0x0012, 0x8801}, /* SSI reg addr */
+ {0x0080, 0x8800}, /* SSI data to write */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802}, /* 375 Khz SSI clock */
+ {0x0012, 0x8801}, /* SSI reg addr */
+ {0x0000, 0x8800}, /* SSI data to write */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802}, /* 375 Khz SSI clock */
+ {0x0011, 0x8801}, /* SSI reg addr */
+ {0x0040, 0x8800}, /* SSI data to write */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0013, 0x8801},
+ {0x0000, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0014, 0x8801},
+ {0x0000, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0015, 0x8801},
+ {0x0001, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0016, 0x8801},
+ {0x0003, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0017, 0x8801},
+ {0x0036, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0018, 0x8801},
+ {0x00ec, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x001a, 0x8801},
+ {0x0094, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x001b, 0x8801},
+ {0x0000, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0027, 0x8801},
+ {0x00a2, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0028, 0x8801},
+ {0x0040, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x002a, 0x8801},
+ {0x0084, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x002b, 0x8801},
+ {0x00a8, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x002c, 0x8801},
+ {0x00fe, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x002d, 0x8801},
+ {0x0003, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0038, 0x8801},
+ {0x0083, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0033, 0x8801},
+ {0x0081, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0034, 0x8801},
+ {0x004a, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0039, 0x8801},
+ {0x0000, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0010, 0x8801},
+ {0x00a8, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0006, 0x8801},
+ {0x0058, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0000, 0x8801},
+ {0x0004, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0040, 0x8801},
+ {0x0080, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0041, 0x8801},
+ {0x000c, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0042, 0x8801},
+ {0x000c, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0043, 0x8801},
+ {0x0028, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0044, 0x8801},
+ {0x0080, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0045, 0x8801},
+ {0x0020, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0046, 0x8801},
+ {0x0020, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0047, 0x8801},
+ {0x0080, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0048, 0x8801},
+ {0x004c, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x0049, 0x8801},
+ {0x0084, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x004a, 0x8801},
+ {0x0084, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x0008, 0x8802},
+ {0x004b, 0x8801},
+ {0x0084, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
/* --------------------------------------- */
- /* 50132 2039 */ {0x0012, 0x8700},
- /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
- /* 50157 2040 */ {0x0000, 0x8701},
- /* CKx1 clock delay adj */
- /* 50182 2041 */ {0x0000, 0x8701},
- /* CKx1 clock delay adj */
- /* 50207 2042 */ {0x0001, 0x870c},
- /* CKOx2 output */
+ {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ {0x0000, 0x8701}, /* CKx1 clock delay adj */
+ {0x0000, 0x8701}, /* CKx1 clock delay adj */
+ {0x0001, 0x870c}, /* CKOx2 output */
/* --------------------------------------- */
- /* 50232 2043 */ {0x0080, 0x8600},
- /* Line memory read counter (L) */
- /* 50257 2044 */ {0x0001, 0x8606},
- /* reserved */
- /* 50282 2045 */ {0x0064, 0x8607},
- /* Line memory read counter (H) 0x6480=25,728 */
- /* 50307 2046 */ {0x002a, 0x8601},
- /* CDSP sharp interpolation mode,
+ {0x0080, 0x8600}, /* Line memory read counter (L) */
+ {0x0001, 0x8606}, /* reserved */
+ {0x0064, 0x8607}, /* Line memory read counter (H) 0x6480=25,728 */
+ {0x002a, 0x8601}, /* CDSP sharp interpolation mode,
* line sel for color sep, edge enhance enab */
- /* 50332 2047 */ {0x0000, 0x8602},
- /* optical black level for user settng = 0 */
- /* 50357 2048 */ {0x0080, 0x8600},
- /* Line memory read counter (L) */
- /* 50382 2049 */ {0x000a, 0x8603},
- /* optical black level calc mode: auto; optical black offset = 10 */
- /* 50407 2050 */ {0x00df, 0x865b},
- /* Horiz offset for valid pixels (L)=0xdf */
- /* 50432 2051 */ {0x0012, 0x865c},
- /* Vert offset for valid lines (L)=0x12 */
+ {0x0000, 0x8602}, /* optical black level for user settng = 0 */
+ {0x0080, 0x8600}, /* Line memory read counter (L) */
+ {0x000a, 0x8603}, /* optical black level calc mode:
+ * auto; optical black offset = 10 */
+ {0x00df, 0x865b}, /* Horiz offset for valid pixels (L)=0xdf */
+ {0x0012, 0x865c}, /* Vert offset for valid lines (L)=0x12 */
/* The following two lines seem to be the "wrong" resolution. */
/* But perhaps these indicate the actual size of the sensor */
/* rather than the size of the current video mode. */
- /* 50457 2052 */ {0x0058, 0x865d},
- /* Horiz valid pixels (*4) (L) = 352 */
- /* 50482 2053 */ {0x0048, 0x865e},
- /* Vert valid lines (*4) (L) = 288 */
-
- /* 50507 2054 */ {0x0015, 0x8608},
- /* A11 Coef ... */
- /* 50532 2055 */ {0x0030, 0x8609},
- /* 50557 2056 */ {0x00fb, 0x860a},
- /* 50582 2057 */ {0x003e, 0x860b},
- /* 50607 2058 */ {0x00ce, 0x860c},
- /* 50632 2059 */ {0x00f4, 0x860d},
- /* 50657 2060 */ {0x00eb, 0x860e},
- /* 50682 2061 */ {0x00dc, 0x860f},
- /* 50707 2062 */ {0x0039, 0x8610},
- /* 50732 2063 */ {0x0001, 0x8611},
- /* R offset for white balance ... */
- /* 50757 2064 */ {0x0000, 0x8612},
- /* 50782 2065 */ {0x0001, 0x8613},
- /* 50807 2066 */ {0x0000, 0x8614},
- /* 50832 2067 */ {0x005b, 0x8651},
- /* R gain for white balance ... */
- /* 50857 2068 */ {0x0040, 0x8652},
- /* 50882 2069 */ {0x0060, 0x8653},
- /* 50907 2070 */ {0x0040, 0x8654},
- /* 50932 2071 */ {0x0000, 0x8655},
- /* 50957 2072 */ {0x0001, 0x863f},
- /* Fixed gamma correction enable, USB control,
- * lum filter disable, lum noise clip disable */
- /* 50982 2073 */ {0x00a1, 0x8656},
- /* Window1 size 256x256, Windows2 size 64x64,
- * gamma look-up disable, new edge enhancement enable */
- /* 51007 2074 */ {0x0018, 0x8657},
- /* Edge gain high thresh */
- /* 51032 2075 */ {0x0020, 0x8658},
- /* Edge gain low thresh */
- /* 51057 2076 */ {0x000a, 0x8659},
- /* Edge bandwidth high threshold */
- /* 51082 2077 */ {0x0005, 0x865a},
- /* Edge bandwidth low threshold */
+ {0x0058, 0x865d}, /* Horiz valid pixels (*4) (L) = 352 */
+ {0x0048, 0x865e}, /* Vert valid lines (*4) (L) = 288 */
+
+ {0x0015, 0x8608}, /* A11 Coef ... */
+ {0x0030, 0x8609},
+ {0x00fb, 0x860a},
+ {0x003e, 0x860b},
+ {0x00ce, 0x860c},
+ {0x00f4, 0x860d},
+ {0x00eb, 0x860e},
+ {0x00dc, 0x860f},
+ {0x0039, 0x8610},
+ {0x0001, 0x8611}, /* R offset for white balance ... */
+ {0x0000, 0x8612},
+ {0x0001, 0x8613},
+ {0x0000, 0x8614},
+ {0x005b, 0x8651}, /* R gain for white balance ... */
+ {0x0040, 0x8652},
+ {0x0060, 0x8653},
+ {0x0040, 0x8654},
+ {0x0000, 0x8655},
+ {0x0001, 0x863f}, /* Fixed gamma correction enable, USB control,
+ * lum filter disable, lum noise clip disable */
+ {0x00a1, 0x8656}, /* Window1 size 256x256, Windows2 size 64x64,
+ * gamma look-up disable,
+ * new edge enhancement enable */
+ {0x0018, 0x8657}, /* Edge gain high thresh */
+ {0x0020, 0x8658}, /* Edge gain low thresh */
+ {0x000a, 0x8659}, /* Edge bandwidth high threshold */
+ {0x0005, 0x865a}, /* Edge bandwidth low threshold */
/* -------------------------------- */
- /* 51107 2078 */ {0x0030, 0x8112},
- /* Video drop enable, ISO streaming enable */
- /* 51130 2079 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 51154 2080 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 51180 2081 */ {0xa908, 0x8802},
- /* 51205 2082 */ {0x0034, 0x8801},
- /* SSI reg addr */
- /* 51230 2083 */ {0x00ca, 0x8800},
+ {0x0030, 0x8112}, /* Video drop enable, ISO streaming enable */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0xa908, 0x8802},
+ {0x0034, 0x8801}, /* SSI reg addr */
+ {0x00ca, 0x8800},
/* SSI data to write */
- /* 51253 2084 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 51277 2085 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 51301 2086 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 51327 2087 */ {0x1f08, 0x8802},
- /* 51352 2088 */ {0x0006, 0x8801},
- /* 51377 2089 */ {0x0080, 0x8800},
- /* 51400 2090 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0x1f08, 0x8802},
+ {0x0006, 0x8801},
+ {0x0080, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
/* ----- Read back coefs we wrote earlier. */
- /* 51424 2091 */ /* READ { 0, 0x0000, 0x8608 } -> 0000: 15 */
- /* 51448 2092 */ /* READ { 0, 0x0000, 0x8609 } -> 0000: 30 */
- /* 51472 2093 */ /* READ { 0, 0x0000, 0x860a } -> 0000: fb */
- /* 51496 2094 */ /* READ { 0, 0x0000, 0x860b } -> 0000: 3e */
- /* 51520 2095 */ /* READ { 0, 0x0000, 0x860c } -> 0000: ce */
- /* 51544 2096 */ /* READ { 0, 0x0000, 0x860d } -> 0000: f4 */
- /* 51568 2097 */ /* READ { 0, 0x0000, 0x860e } -> 0000: eb */
- /* 51592 2098 */ /* READ { 0, 0x0000, 0x860f } -> 0000: dc */
- /* 51616 2099 */ /* READ { 0, 0x0000, 0x8610 } -> 0000: 39 */
- /* 51640 2100 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 51664 2101 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 08 */
- /* 51690 2102 */ {0xb008, 0x8802},
- /* 51715 2103 */ {0x0006, 0x8801},
- /* 51740 2104 */ {0x007d, 0x8800},
- /* 51763 2105 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0000, 0x8608 } -> 0000: 15 */
+ /* READ { 0x0000, 0x8609 } -> 0000: 30 */
+ /* READ { 0x0000, 0x860a } -> 0000: fb */
+ /* READ { 0x0000, 0x860b } -> 0000: 3e */
+ /* READ { 0x0000, 0x860c } -> 0000: ce */
+ /* READ { 0x0000, 0x860d } -> 0000: f4 */
+ /* READ { 0x0000, 0x860e } -> 0000: eb */
+ /* READ { 0x0000, 0x860f } -> 0000: dc */
+ /* READ { 0x0000, 0x8610 } -> 0000: 39 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 08 */
+ {0xb008, 0x8802},
+ {0x0006, 0x8801},
+ {0x007d, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
#if 0
/* experimental. dark version. */
@@ -504,114 +465,86 @@ static const u16 spca508_init_data[][2] =
/* earlier commands (A11 Coef...), but if I disable it, */
/* the image appears too dark. Maybe there was some kind of */
/* reset since the earlier commands, so this is necessary again. */
- /* 51789 2106 */ {0x0015, 0x8608},
- /* 51814 2107 */ {0x0030, 0x8609},
- /* 51839 2108 */ {0xfffb, 0x860a},
- /* 51864 2109 */ {0x003e, 0x860b},
- /* 51889 2110 */ {0xffce, 0x860c},
- /* 51914 2111 */ {0xfff4, 0x860d},
- /* 51939 2112 */ {0xffeb, 0x860e},
- /* 51964 2113 */ {0xffdc, 0x860f},
- /* 51989 2114 */ {0x0039, 0x8610},
- /* 52014 2115 */ {0x0018, 0x8657},
+ {0x0015, 0x8608},
+ {0x0030, 0x8609},
+ {0xfffb, 0x860a},
+ {0x003e, 0x860b},
+ {0xffce, 0x860c},
+ {0xfff4, 0x860d},
+ {0xffeb, 0x860e},
+ {0xffdc, 0x860f},
+ {0x0039, 0x8610},
+ {0x0018, 0x8657},
#endif
- /* 52039 2116 */ {0x0000, 0x8508},
- /* Disable compression. */
+ {0x0000, 0x8508}, /* Disable compression. */
/* Previous line was:
- * 52039 2116 * { 0, 0x0021, 0x8508 }, * Enable compression. */
- /* 52064 2117 */ {0x0032, 0x850b},
- /* compression stuff */
- /* 52089 2118 */ {0x0003, 0x8509},
- /* compression stuff */
- /* 52114 2119 */ {0x0011, 0x850a},
- /* compression stuff */
- /* 52139 2120 */ {0x0021, 0x850d},
- /* compression stuff */
- /* 52164 2121 */ {0x0010, 0x850c},
- /* compression stuff */
- /* 52189 2122 */ {0x0003, 0x8500},
- /* *** Video mode: 160x120 */
- /* 52214 2123 */ {0x0001, 0x8501},
- /* Hardware-dominated snap control */
- /* 52239 2124 */ {0x0061, 0x8656},
- /* Window1 size 128x128, Windows2 size 128x128,
- * gamma look-up disable, new edge enhancement enable */
- /* 52264 2125 */ {0x0018, 0x8617},
- /* Window1 start X (*2) */
- /* 52289 2126 */ {0x0008, 0x8618},
- /* Window1 start Y (*2) */
- /* 52314 2127 */ {0x0061, 0x8656},
- /* Window1 size 128x128, Windows2 size 128x128,
- * gamma look-up disable, new edge enhancement enable */
- /* 52339 2128 */ {0x0058, 0x8619},
- /* Window2 start X (*2) */
- /* 52364 2129 */ {0x0008, 0x861a},
- /* Window2 start Y (*2) */
- /* 52389 2130 */ {0x00ff, 0x8615},
- /* High lum thresh for white balance */
- /* 52414 2131 */ {0x0000, 0x8616},
- /* Low lum thresh for white balance */
- /* 52439 2132 */ {0x0012, 0x8700},
- /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
- /* 52464 2133 */ {0x0012, 0x8700},
- /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
- /* 52487 2134 */ /* READ { 0, 0x0000, 0x8656 } -> 0000: 61 */
- /* 52513 2135 */ {0x0028, 0x8802},
- /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
- /* 52536 2136 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 52560 2137 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */
- /* 52586 2138 */ {0x1f28, 0x8802},
- /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
- /* 52611 2139 */ {0x0010, 0x8801},
- /* SSI reg addr */
- /* 52636 2140 */ {0x003e, 0x8800},
- /* SSI data to write */
- /* 52659 2141 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 52685 2142 */ {0x0028, 0x8802},
- /* 52708 2143 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 52732 2144 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */
- /* 52758 2145 */ {0x1f28, 0x8802},
- /* 52783 2146 */ {0x0000, 0x8801},
- /* 52808 2147 */ {0x001f, 0x8800},
- /* 52831 2148 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 52857 2149 */ {0x0001, 0x8602},
- /* optical black level for user settning = 1 */
+ {0x0021, 0x8508}, * Enable compression. */
+ {0x0032, 0x850b}, /* compression stuff */
+ {0x0003, 0x8509}, /* compression stuff */
+ {0x0011, 0x850a}, /* compression stuff */
+ {0x0021, 0x850d}, /* compression stuff */
+ {0x0010, 0x850c}, /* compression stuff */
+ {0x0003, 0x8500}, /* *** Video mode: 160x120 */
+ {0x0001, 0x8501}, /* Hardware-dominated snap control */
+ {0x0061, 0x8656}, /* Window1 size 128x128, Windows2 size 128x128,
+ * gamma look-up disable,
+ * new edge enhancement enable */
+ {0x0018, 0x8617}, /* Window1 start X (*2) */
+ {0x0008, 0x8618}, /* Window1 start Y (*2) */
+ {0x0061, 0x8656}, /* Window1 size 128x128, Windows2 size 128x128,
+ * gamma look-up disable,
+ * new edge enhancement enable */
+ {0x0058, 0x8619}, /* Window2 start X (*2) */
+ {0x0008, 0x861a}, /* Window2 start Y (*2) */
+ {0x00ff, 0x8615}, /* High lum thresh for white balance */
+ {0x0000, 0x8616}, /* Low lum thresh for white balance */
+ {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ {0x0012, 0x8700}, /* Clock speed 48Mhz/(2+2)/2= 6 Mhz */
+ /* READ { 0x0000, 0x8656 } -> 0000: 61 */
+ {0x0028, 0x8802}, /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 28 */
+ {0x1f28, 0x8802}, /* 375 Khz SSI clock, SSI r/w sync with VSYNC */
+ {0x0010, 0x8801}, /* SSI reg addr */
+ {0x003e, 0x8800}, /* SSI data to write */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ {0x0028, 0x8802},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 28 */
+ {0x1f28, 0x8802},
+ {0x0000, 0x8801},
+ {0x001f, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ {0x0001, 0x8602}, /* optical black level for user settning = 1 */
#if 0
/* NOTE: Code like this case lets this driver (often) work */
/* in 352x288 resolution, apparently by slowing down the */
/* clock. */
- /* 52464 2133 */ {0x002F, 0x8700},
- /* Clock speed */
+ {0x002f, 0x8700}, /* Clock speed */
#else
/* Original: */
- /* 52882 2150 */ {0x0023, 0x8700},
- /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
+ {0x0023, 0x8700}, /* Clock speed 48Mhz/(3+2)/4= 2.4 Mhz */
#endif
- /* 52907 2151 */ {0x000f, 0x8602},
- /* optical black level for user settning = 15 */
-
- /* 52932 2152 */ {0x0028, 0x8802},
- /* 52955 2153 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 52979 2154 */ /* READ { 0, 0x0001, 0x8802 } -> 0000: 28 */
- /* 53005 2155 */ {0x1f28, 0x8802},
- /* 53030 2156 */ {0x0010, 0x8801},
- /* 53055 2157 */ {0x007b, 0x8800},
- /* 53078 2158 */ /* READ { 0, 0x0001, 0x8803 } -> 0000: 00 */
- /* 53104 2159 */ {0x002f, 0x8651},
- /* R gain for white balance ... */
- /* 53129 2160 */ {0x0080, 0x8653},
- /* 53152 2161 */ /* READ { 0, 0x0000, 0x8655 } -> 0000: 00 */
- /* 53178 2162 */ {0x0000, 0x8655},
-
- /* 53203 2163 */ {0x0030, 0x8112},
- /* Video drop enable, ISO streaming enable */
- /* 53228 2164 */ {0x0020, 0x8112},
- /* Video drop enable, ISO streaming disable */
- /* 53252 2165 */
- /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
+ {0x000f, 0x8602}, /* optical black level for user settning = 15 */
+
+ {0x0028, 0x8802},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 28 */
+ {0x1f28, 0x8802},
+ {0x0010, 0x8801},
+ {0x007b, 0x8800},
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ {0x002f, 0x8651}, /* R gain for white balance ... */
+ {0x0080, 0x8653},
+ /* READ { 0x0000, 0x8655 } -> 0000: 00 */
+ {0x0000, 0x8655},
+
+ {0x0030, 0x8112}, /* Video drop enable, ISO streaming enable */
+ {0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */
+ /* UNKNOWN DIRECTION (URB_FUNCTION_SELECT_INTERFACE: (ALT=0) ) */
{}
};
@@ -619,27 +552,27 @@ static const u16 spca508_init_data[][2] =
* Initialization data for Intel EasyPC Camera CS110
*/
static const u16 spca508cs110_init_data[][2] = {
- {0x0000, 0x870b}, /* Reset CTL3 */
- {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
- {0x0000, 0x8111}, /* Normal operation on reset */
+ {0x0000, 0x870b}, /* Reset CTL3 */
+ {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
+ {0x0000, 0x8111}, /* Normal operation on reset */
{0x0090, 0x8110},
/* External Clock 2x & Synchronous Serial Interface Output */
- {0x0020, 0x8112}, /* Video Drop packet enable */
- {0x0000, 0x8114}, /* Software GPIO output data */
+ {0x0020, 0x8112}, /* Video Drop packet enable */
+ {0x0000, 0x8114}, /* Software GPIO output data */
{0x0001, 0x8114},
{0x0001, 0x8114},
{0x0001, 0x8114},
{0x0003, 0x8114},
/* Initial sequence Synchronous Serial Interface */
- {0x000f, 0x8402}, /* Memory bank Address */
- {0x0000, 0x8403}, /* Memory bank Address */
- {0x00ba, 0x8804}, /* SSI Slave address */
- {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
- {0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */
+ {0x000f, 0x8402}, /* Memory bank Address */
+ {0x0000, 0x8403}, /* Memory bank Address */
+ {0x00ba, 0x8804}, /* SSI Slave address */
+ {0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
+ {0x0010, 0x8802}, /* 93.75kHz SSI Clock two DataByte */
{0x0001, 0x8801},
- {0x000a, 0x8805},/* a - NWG: Dunno what this is about */
+ {0x000a, 0x8805}, /* a - NWG: Dunno what this is about */
{0x0000, 0x8800},
{0x0010, 0x8802},
@@ -673,459 +606,459 @@ static const u16 spca508cs110_init_data[][2] = {
{0x0000, 0x8800},
{0x0010, 0x8802},
- {0x0002, 0x8704}, /* External input CKIx1 */
- {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
- {0x009a, 0x8600}, /* Line memory Read Counter (L) */
- {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */
- {0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */
- {0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */
+ {0x0002, 0x8704}, /* External input CKIx1 */
+ {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
+ {0x009a, 0x8600}, /* Line memory Read Counter (L) */
+ {0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */
+ {0x0003, 0x865c}, /* 3 Vertical Offset for Valid Lines(L) */
+ {0x0058, 0x865d}, /* 58 Horizontal Valid Pixel Window(L) */
- {0x0006, 0x8660}, /* Nibble data + input order */
+ {0x0006, 0x8660}, /* Nibble data + input order */
- {0x000a, 0x8602}, /* Optical black level set to 0x0a */
-/* 1945 */ {0x0000, 0x8603}, /* Optical black level Offset */
+ {0x000a, 0x8602}, /* Optical black level set to 0x0a */
+ {0x0000, 0x8603}, /* Optical black level Offset */
-/* 1962 * {0, 0x0000, 0x8611}, * 0 R Offset for white Balance */
-/* 1963 * {0, 0x0000, 0x8612}, * 1 Gr Offset for white Balance */
-/* 1964 * {0, 0x0000, 0x8613}, * 1f B Offset for white Balance */
-/* 1965 * {0, 0x0000, 0x8614}, * f0 Gb Offset for white Balance */
+/* {0x0000, 0x8611}, * 0 R Offset for white Balance */
+/* {0x0000, 0x8612}, * 1 Gr Offset for white Balance */
+/* {0x0000, 0x8613}, * 1f B Offset for white Balance */
+/* {0x0000, 0x8614}, * f0 Gb Offset for white Balance */
- {0x0040, 0x8651}, /* 2b BLUE gain for white balance good at all 60 */
- {0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */
- {0x0035, 0x8653}, /* 26 RED gain for white balance */
- {0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */
+ {0x0040, 0x8651}, /* 2b BLUE gain for white balance good at all 60 */
+ {0x0030, 0x8652}, /* 41 Gr Gain for white Balance (L) */
+ {0x0035, 0x8653}, /* 26 RED gain for white balance */
+ {0x0035, 0x8654}, /* 40Gb Gain for white Balance (L) */
{0x0041, 0x863f},
/* Fixed Gamma correction enabled (makes colours look better) */
-/* 2422 */ {0x0000, 0x8655},
- /* High bits for white balance*****brightness control*** */
+ {0x0000, 0x8655},
+ /* High bits for white balance*****brightness control*** */
{}
};
static const u16 spca508_sightcam_init_data[][2] = {
/* This line seems to setup the frame/canvas */
- /*368 */ {0x000f, 0x8402},
+ {0x000f, 0x8402},
/* Theese 6 lines are needed to startup the webcam */
- /*398 */ {0x0090, 0x8110},
- /*399 */ {0x0001, 0x8114},
- /*400 */ {0x0001, 0x8114},
- /*401 */ {0x0001, 0x8114},
- /*402 */ {0x0003, 0x8114},
- /*403 */ {0x0080, 0x8804},
+ {0x0090, 0x8110},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0003, 0x8114},
+ {0x0080, 0x8804},
/* This part seems to make the pictures darker? (autobrightness?) */
- /*436 */ {0x0001, 0x8801},
- /*437 */ {0x0004, 0x8800},
- /*439 */ {0x0003, 0x8801},
- /*440 */ {0x00e0, 0x8800},
- /*442 */ {0x0004, 0x8801},
- /*443 */ {0x00b4, 0x8800},
- /*445 */ {0x0005, 0x8801},
- /*446 */ {0x0000, 0x8800},
-
- /*448 */ {0x0006, 0x8801},
- /*449 */ {0x00e0, 0x8800},
- /*451 */ {0x0007, 0x8801},
- /*452 */ {0x000c, 0x8800},
+ {0x0001, 0x8801},
+ {0x0004, 0x8800},
+ {0x0003, 0x8801},
+ {0x00e0, 0x8800},
+ {0x0004, 0x8801},
+ {0x00b4, 0x8800},
+ {0x0005, 0x8801},
+ {0x0000, 0x8800},
+
+ {0x0006, 0x8801},
+ {0x00e0, 0x8800},
+ {0x0007, 0x8801},
+ {0x000c, 0x8800},
/* This section is just needed, it probably
* does something like the previous section,
* but the cam won't start if it's not included.
*/
- /*484 */ {0x0014, 0x8801},
- /*485 */ {0x0008, 0x8800},
- /*487 */ {0x0015, 0x8801},
- /*488 */ {0x0067, 0x8800},
- /*490 */ {0x0016, 0x8801},
- /*491 */ {0x0000, 0x8800},
- /*493 */ {0x0017, 0x8801},
- /*494 */ {0x0020, 0x8800},
- /*496 */ {0x0018, 0x8801},
- /*497 */ {0x0044, 0x8800},
+ {0x0014, 0x8801},
+ {0x0008, 0x8800},
+ {0x0015, 0x8801},
+ {0x0067, 0x8800},
+ {0x0016, 0x8801},
+ {0x0000, 0x8800},
+ {0x0017, 0x8801},
+ {0x0020, 0x8800},
+ {0x0018, 0x8801},
+ {0x0044, 0x8800},
/* Makes the picture darker - and the
* cam won't start if not included
*/
- /*505 */ {0x001e, 0x8801},
- /*506 */ {0x00ea, 0x8800},
- /*508 */ {0x001f, 0x8801},
- /*509 */ {0x0001, 0x8800},
- /*511 */ {0x0003, 0x8801},
- /*512 */ {0x00e0, 0x8800},
+ {0x001e, 0x8801},
+ {0x00ea, 0x8800},
+ {0x001f, 0x8801},
+ {0x0001, 0x8800},
+ {0x0003, 0x8801},
+ {0x00e0, 0x8800},
/* seems to place the colors ontop of each other #1 */
- /*517 */ {0x0006, 0x8704},
- /*518 */ {0x0001, 0x870c},
- /*519 */ {0x0016, 0x8600},
- /*520 */ {0x0002, 0x8606},
+ {0x0006, 0x8704},
+ {0x0001, 0x870c},
+ {0x0016, 0x8600},
+ {0x0002, 0x8606},
/* if not included the pictures becomes _very_ dark */
- /*521 */ {0x0064, 0x8607},
- /*522 */ {0x003a, 0x8601},
- /*523 */ {0x0000, 0x8602},
+ {0x0064, 0x8607},
+ {0x003a, 0x8601},
+ {0x0000, 0x8602},
/* seems to place the colors ontop of each other #2 */
- /*524 */ {0x0016, 0x8600},
- /*525 */ {0x0018, 0x8617},
- /*526 */ {0x0008, 0x8618},
- /*527 */ {0x00a1, 0x8656},
+ {0x0016, 0x8600},
+ {0x0018, 0x8617},
+ {0x0008, 0x8618},
+ {0x00a1, 0x8656},
/* webcam won't start if not included */
- /*528 */ {0x0007, 0x865b},
- /*529 */ {0x0001, 0x865c},
- /*530 */ {0x0058, 0x865d},
- /*531 */ {0x0048, 0x865e},
+ {0x0007, 0x865b},
+ {0x0001, 0x865c},
+ {0x0058, 0x865d},
+ {0x0048, 0x865e},
/* adjusts the colors */
- /*541 */ {0x0049, 0x8651},
- /*542 */ {0x0040, 0x8652},
- /*543 */ {0x004c, 0x8653},
- /*544 */ {0x0040, 0x8654},
+ {0x0049, 0x8651},
+ {0x0040, 0x8652},
+ {0x004c, 0x8653},
+ {0x0040, 0x8654},
{}
};
static const u16 spca508_sightcam2_init_data[][2] = {
-/* 35 */ {0x0020, 0x8112},
-
-/* 36 */ {0x000f, 0x8402},
-/* 37 */ {0x0000, 0x8403},
-
-/* 38 */ {0x0008, 0x8201},
-/* 39 */ {0x0008, 0x8200},
-/* 40 */ {0x0001, 0x8200},
-/* 43 */ {0x0009, 0x8201},
-/* 44 */ {0x0008, 0x8200},
-/* 45 */ {0x0001, 0x8200},
-/* 48 */ {0x000a, 0x8201},
-/* 49 */ {0x0008, 0x8200},
-/* 50 */ {0x0001, 0x8200},
-/* 53 */ {0x000b, 0x8201},
-/* 54 */ {0x0008, 0x8200},
-/* 55 */ {0x0001, 0x8200},
-/* 58 */ {0x000c, 0x8201},
-/* 59 */ {0x0008, 0x8200},
-/* 60 */ {0x0001, 0x8200},
-/* 63 */ {0x000d, 0x8201},
-/* 64 */ {0x0008, 0x8200},
-/* 65 */ {0x0001, 0x8200},
-/* 68 */ {0x000e, 0x8201},
-/* 69 */ {0x0008, 0x8200},
-/* 70 */ {0x0001, 0x8200},
-/* 73 */ {0x0007, 0x8201},
-/* 74 */ {0x0008, 0x8200},
-/* 75 */ {0x0001, 0x8200},
-/* 78 */ {0x000f, 0x8201},
-/* 79 */ {0x0008, 0x8200},
-/* 80 */ {0x0001, 0x8200},
-
-/* 84 */ {0x0018, 0x8660},
-/* 85 */ {0x0010, 0x8201},
-
-/* 86 */ {0x0008, 0x8200},
-/* 87 */ {0x0001, 0x8200},
-/* 90 */ {0x0011, 0x8201},
-/* 91 */ {0x0008, 0x8200},
-/* 92 */ {0x0001, 0x8200},
-
-/* 95 */ {0x0000, 0x86b0},
-/* 96 */ {0x0034, 0x86b1},
-/* 97 */ {0x0000, 0x86b2},
-/* 98 */ {0x0049, 0x86b3},
-/* 99 */ {0x0000, 0x86b4},
-/* 100 */ {0x0000, 0x86b4},
-
-/* 101 */ {0x0012, 0x8201},
-/* 102 */ {0x0008, 0x8200},
-/* 103 */ {0x0001, 0x8200},
-/* 106 */ {0x0013, 0x8201},
-/* 107 */ {0x0008, 0x8200},
-/* 108 */ {0x0001, 0x8200},
-
-/* 111 */ {0x0001, 0x86b0},
-/* 112 */ {0x00aa, 0x86b1},
-/* 113 */ {0x0000, 0x86b2},
-/* 114 */ {0x00e4, 0x86b3},
-/* 115 */ {0x0000, 0x86b4},
-/* 116 */ {0x0000, 0x86b4},
-
-/* 118 */ {0x0018, 0x8660},
-
-/* 119 */ {0x0090, 0x8110},
-/* 120 */ {0x0001, 0x8114},
-/* 121 */ {0x0001, 0x8114},
-/* 122 */ {0x0001, 0x8114},
-/* 123 */ {0x0003, 0x8114},
-
-/* 124 */ {0x0080, 0x8804},
-/* 157 */ {0x0003, 0x8801},
-/* 158 */ {0x0012, 0x8800},
-/* 160 */ {0x0004, 0x8801},
-/* 161 */ {0x0005, 0x8800},
-/* 163 */ {0x0005, 0x8801},
-/* 164 */ {0x0000, 0x8800},
-/* 166 */ {0x0006, 0x8801},
-/* 167 */ {0x0000, 0x8800},
-/* 169 */ {0x0007, 0x8801},
-/* 170 */ {0x0000, 0x8800},
-/* 172 */ {0x0008, 0x8801},
-/* 173 */ {0x0005, 0x8800},
-/* 175 */ {0x000a, 0x8700},
-/* 176 */ {0x000e, 0x8801},
-/* 177 */ {0x0004, 0x8800},
-/* 179 */ {0x0005, 0x8801},
-/* 180 */ {0x0047, 0x8800},
-/* 182 */ {0x0006, 0x8801},
-/* 183 */ {0x0000, 0x8800},
-/* 185 */ {0x0007, 0x8801},
-/* 186 */ {0x00c0, 0x8800},
-/* 188 */ {0x0008, 0x8801},
-/* 189 */ {0x0003, 0x8800},
-/* 191 */ {0x0013, 0x8801},
-/* 192 */ {0x0001, 0x8800},
-/* 194 */ {0x0009, 0x8801},
-/* 195 */ {0x0000, 0x8800},
-/* 197 */ {0x000a, 0x8801},
-/* 198 */ {0x0000, 0x8800},
-/* 200 */ {0x000b, 0x8801},
-/* 201 */ {0x0000, 0x8800},
-/* 203 */ {0x000c, 0x8801},
-/* 204 */ {0x0000, 0x8800},
-/* 206 */ {0x000e, 0x8801},
-/* 207 */ {0x0004, 0x8800},
-/* 209 */ {0x000f, 0x8801},
-/* 210 */ {0x0000, 0x8800},
-/* 212 */ {0x0010, 0x8801},
-/* 213 */ {0x0006, 0x8800},
-/* 215 */ {0x0011, 0x8801},
-/* 216 */ {0x0006, 0x8800},
-/* 218 */ {0x0012, 0x8801},
-/* 219 */ {0x0000, 0x8800},
-/* 221 */ {0x0013, 0x8801},
-/* 222 */ {0x0001, 0x8800},
-
-/* 224 */ {0x000a, 0x8700},
-/* 225 */ {0x0000, 0x8702},
-/* 226 */ {0x0000, 0x8703},
-/* 227 */ {0x00c2, 0x8704},
-/* 228 */ {0x0001, 0x870c},
-
-/* 229 */ {0x0044, 0x8600},
-/* 230 */ {0x0002, 0x8606},
-/* 231 */ {0x0064, 0x8607},
-/* 232 */ {0x003a, 0x8601},
-/* 233 */ {0x0008, 0x8602},
-/* 234 */ {0x0044, 0x8600},
-/* 235 */ {0x0018, 0x8617},
-/* 236 */ {0x0008, 0x8618},
-/* 237 */ {0x00a1, 0x8656},
-/* 238 */ {0x0004, 0x865b},
-/* 239 */ {0x0002, 0x865c},
-/* 240 */ {0x0058, 0x865d},
-/* 241 */ {0x0048, 0x865e},
-/* 242 */ {0x0012, 0x8608},
-/* 243 */ {0x002c, 0x8609},
-/* 244 */ {0x0002, 0x860a},
-/* 245 */ {0x002c, 0x860b},
-/* 246 */ {0x00db, 0x860c},
-/* 247 */ {0x00f9, 0x860d},
-/* 248 */ {0x00f1, 0x860e},
-/* 249 */ {0x00e3, 0x860f},
-/* 250 */ {0x002c, 0x8610},
-/* 251 */ {0x006c, 0x8651},
-/* 252 */ {0x0041, 0x8652},
-/* 253 */ {0x0059, 0x8653},
-/* 254 */ {0x0040, 0x8654},
-/* 255 */ {0x00fa, 0x8611},
-/* 256 */ {0x00ff, 0x8612},
-/* 257 */ {0x00f8, 0x8613},
-/* 258 */ {0x0000, 0x8614},
-/* 259 */ {0x0001, 0x863f},
-/* 260 */ {0x0000, 0x8640},
-/* 261 */ {0x0026, 0x8641},
-/* 262 */ {0x0045, 0x8642},
-/* 263 */ {0x0060, 0x8643},
-/* 264 */ {0x0075, 0x8644},
-/* 265 */ {0x0088, 0x8645},
-/* 266 */ {0x009b, 0x8646},
-/* 267 */ {0x00b0, 0x8647},
-/* 268 */ {0x00c5, 0x8648},
-/* 269 */ {0x00d2, 0x8649},
-/* 270 */ {0x00dc, 0x864a},
-/* 271 */ {0x00e5, 0x864b},
-/* 272 */ {0x00eb, 0x864c},
-/* 273 */ {0x00f0, 0x864d},
-/* 274 */ {0x00f6, 0x864e},
-/* 275 */ {0x00fa, 0x864f},
-/* 276 */ {0x00ff, 0x8650},
-/* 277 */ {0x0060, 0x8657},
-/* 278 */ {0x0010, 0x8658},
-/* 279 */ {0x0018, 0x8659},
-/* 280 */ {0x0005, 0x865a},
-/* 281 */ {0x0018, 0x8660},
-/* 282 */ {0x0003, 0x8509},
-/* 283 */ {0x0011, 0x850a},
-/* 284 */ {0x0032, 0x850b},
-/* 285 */ {0x0010, 0x850c},
-/* 286 */ {0x0021, 0x850d},
-/* 287 */ {0x0001, 0x8500},
-/* 288 */ {0x0000, 0x8508},
-/* 289 */ {0x0012, 0x8608},
-/* 290 */ {0x002c, 0x8609},
-/* 291 */ {0x0002, 0x860a},
-/* 292 */ {0x0039, 0x860b},
-/* 293 */ {0x00d0, 0x860c},
-/* 294 */ {0x00f7, 0x860d},
-/* 295 */ {0x00ed, 0x860e},
-/* 296 */ {0x00db, 0x860f},
-/* 297 */ {0x0039, 0x8610},
-/* 298 */ {0x0012, 0x8657},
-/* 299 */ {0x000c, 0x8619},
-/* 300 */ {0x0004, 0x861a},
-/* 301 */ {0x00a1, 0x8656},
-/* 302 */ {0x00c8, 0x8615},
-/* 303 */ {0x0032, 0x8616},
-
-/* 306 */ {0x0030, 0x8112},
-/* 313 */ {0x0020, 0x8112},
-/* 314 */ {0x0020, 0x8112},
-/* 315 */ {0x000f, 0x8402},
-/* 316 */ {0x0000, 0x8403},
-
-/* 317 */ {0x0090, 0x8110},
-/* 318 */ {0x0001, 0x8114},
-/* 319 */ {0x0001, 0x8114},
-/* 320 */ {0x0001, 0x8114},
-/* 321 */ {0x0003, 0x8114},
-/* 322 */ {0x0080, 0x8804},
-
-/* 355 */ {0x0003, 0x8801},
-/* 356 */ {0x0012, 0x8800},
-/* 358 */ {0x0004, 0x8801},
-/* 359 */ {0x0005, 0x8800},
-/* 361 */ {0x0005, 0x8801},
-/* 362 */ {0x0047, 0x8800},
-/* 364 */ {0x0006, 0x8801},
-/* 365 */ {0x0000, 0x8800},
-/* 367 */ {0x0007, 0x8801},
-/* 368 */ {0x00c0, 0x8800},
-/* 370 */ {0x0008, 0x8801},
-/* 371 */ {0x0003, 0x8800},
-/* 373 */ {0x000a, 0x8700},
-/* 374 */ {0x000e, 0x8801},
-/* 375 */ {0x0004, 0x8800},
-/* 377 */ {0x0005, 0x8801},
-/* 378 */ {0x0047, 0x8800},
-/* 380 */ {0x0006, 0x8801},
-/* 381 */ {0x0000, 0x8800},
-/* 383 */ {0x0007, 0x8801},
-/* 384 */ {0x00c0, 0x8800},
-/* 386 */ {0x0008, 0x8801},
-/* 387 */ {0x0003, 0x8800},
-/* 389 */ {0x0013, 0x8801},
-/* 390 */ {0x0001, 0x8800},
-/* 392 */ {0x0009, 0x8801},
-/* 393 */ {0x0000, 0x8800},
-/* 395 */ {0x000a, 0x8801},
-/* 396 */ {0x0000, 0x8800},
-/* 398 */ {0x000b, 0x8801},
-/* 399 */ {0x0000, 0x8800},
-/* 401 */ {0x000c, 0x8801},
-/* 402 */ {0x0000, 0x8800},
-/* 404 */ {0x000e, 0x8801},
-/* 405 */ {0x0004, 0x8800},
-/* 407 */ {0x000f, 0x8801},
-/* 408 */ {0x0000, 0x8800},
-/* 410 */ {0x0010, 0x8801},
-/* 411 */ {0x0006, 0x8800},
-/* 413 */ {0x0011, 0x8801},
-/* 414 */ {0x0006, 0x8800},
-/* 416 */ {0x0012, 0x8801},
-/* 417 */ {0x0000, 0x8800},
-/* 419 */ {0x0013, 0x8801},
-/* 420 */ {0x0001, 0x8800},
-/* 422 */ {0x000a, 0x8700},
-/* 423 */ {0x0000, 0x8702},
-/* 424 */ {0x0000, 0x8703},
-/* 425 */ {0x00c2, 0x8704},
-/* 426 */ {0x0001, 0x870c},
-/* 427 */ {0x0044, 0x8600},
-/* 428 */ {0x0002, 0x8606},
-/* 429 */ {0x0064, 0x8607},
-/* 430 */ {0x003a, 0x8601},
-/* 431 */ {0x0008, 0x8602},
-/* 432 */ {0x0044, 0x8600},
-/* 433 */ {0x0018, 0x8617},
-/* 434 */ {0x0008, 0x8618},
-/* 435 */ {0x00a1, 0x8656},
-/* 436 */ {0x0004, 0x865b},
-/* 437 */ {0x0002, 0x865c},
-/* 438 */ {0x0058, 0x865d},
-/* 439 */ {0x0048, 0x865e},
-/* 440 */ {0x0012, 0x8608},
-/* 441 */ {0x002c, 0x8609},
-/* 442 */ {0x0002, 0x860a},
-/* 443 */ {0x002c, 0x860b},
-/* 444 */ {0x00db, 0x860c},
-/* 445 */ {0x00f9, 0x860d},
-/* 446 */ {0x00f1, 0x860e},
-/* 447 */ {0x00e3, 0x860f},
-/* 448 */ {0x002c, 0x8610},
-/* 449 */ {0x006c, 0x8651},
-/* 450 */ {0x0041, 0x8652},
-/* 451 */ {0x0059, 0x8653},
-/* 452 */ {0x0040, 0x8654},
-/* 453 */ {0x00fa, 0x8611},
-/* 454 */ {0x00ff, 0x8612},
-/* 455 */ {0x00f8, 0x8613},
-/* 456 */ {0x0000, 0x8614},
-/* 457 */ {0x0001, 0x863f},
-/* 458 */ {0x0000, 0x8640},
-/* 459 */ {0x0026, 0x8641},
-/* 460 */ {0x0045, 0x8642},
-/* 461 */ {0x0060, 0x8643},
-/* 462 */ {0x0075, 0x8644},
-/* 463 */ {0x0088, 0x8645},
-/* 464 */ {0x009b, 0x8646},
-/* 465 */ {0x00b0, 0x8647},
-/* 466 */ {0x00c5, 0x8648},
-/* 467 */ {0x00d2, 0x8649},
-/* 468 */ {0x00dc, 0x864a},
-/* 469 */ {0x00e5, 0x864b},
-/* 470 */ {0x00eb, 0x864c},
-/* 471 */ {0x00f0, 0x864d},
-/* 472 */ {0x00f6, 0x864e},
-/* 473 */ {0x00fa, 0x864f},
-/* 474 */ {0x00ff, 0x8650},
-/* 475 */ {0x0060, 0x8657},
-/* 476 */ {0x0010, 0x8658},
-/* 477 */ {0x0018, 0x8659},
-/* 478 */ {0x0005, 0x865a},
-/* 479 */ {0x0018, 0x8660},
-/* 480 */ {0x0003, 0x8509},
-/* 481 */ {0x0011, 0x850a},
-/* 482 */ {0x0032, 0x850b},
-/* 483 */ {0x0010, 0x850c},
-/* 484 */ {0x0021, 0x850d},
-/* 485 */ {0x0001, 0x8500},
-/* 486 */ {0x0000, 0x8508},
-
-/* 487 */ {0x0012, 0x8608},
-/* 488 */ {0x002c, 0x8609},
-/* 489 */ {0x0002, 0x860a},
-/* 490 */ {0x0039, 0x860b},
-/* 491 */ {0x00d0, 0x860c},
-/* 492 */ {0x00f7, 0x860d},
-/* 493 */ {0x00ed, 0x860e},
-/* 494 */ {0x00db, 0x860f},
-/* 495 */ {0x0039, 0x8610},
-/* 496 */ {0x0012, 0x8657},
-/* 497 */ {0x0064, 0x8619},
+ {0x0020, 0x8112},
+
+ {0x000f, 0x8402},
+ {0x0000, 0x8403},
+
+ {0x0008, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x0009, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000a, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000b, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000c, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000d, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000e, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x0007, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x000f, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+
+ {0x0018, 0x8660},
+ {0x0010, 0x8201},
+
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x0011, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+
+ {0x0000, 0x86b0},
+ {0x0034, 0x86b1},
+ {0x0000, 0x86b2},
+ {0x0049, 0x86b3},
+ {0x0000, 0x86b4},
+ {0x0000, 0x86b4},
+
+ {0x0012, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+ {0x0013, 0x8201},
+ {0x0008, 0x8200},
+ {0x0001, 0x8200},
+
+ {0x0001, 0x86b0},
+ {0x00aa, 0x86b1},
+ {0x0000, 0x86b2},
+ {0x00e4, 0x86b3},
+ {0x0000, 0x86b4},
+ {0x0000, 0x86b4},
+
+ {0x0018, 0x8660},
+
+ {0x0090, 0x8110},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0003, 0x8114},
+
+ {0x0080, 0x8804},
+ {0x0003, 0x8801},
+ {0x0012, 0x8800},
+ {0x0004, 0x8801},
+ {0x0005, 0x8800},
+ {0x0005, 0x8801},
+ {0x0000, 0x8800},
+ {0x0006, 0x8801},
+ {0x0000, 0x8800},
+ {0x0007, 0x8801},
+ {0x0000, 0x8800},
+ {0x0008, 0x8801},
+ {0x0005, 0x8800},
+ {0x000a, 0x8700},
+ {0x000e, 0x8801},
+ {0x0004, 0x8800},
+ {0x0005, 0x8801},
+ {0x0047, 0x8800},
+ {0x0006, 0x8801},
+ {0x0000, 0x8800},
+ {0x0007, 0x8801},
+ {0x00c0, 0x8800},
+ {0x0008, 0x8801},
+ {0x0003, 0x8800},
+ {0x0013, 0x8801},
+ {0x0001, 0x8800},
+ {0x0009, 0x8801},
+ {0x0000, 0x8800},
+ {0x000a, 0x8801},
+ {0x0000, 0x8800},
+ {0x000b, 0x8801},
+ {0x0000, 0x8800},
+ {0x000c, 0x8801},
+ {0x0000, 0x8800},
+ {0x000e, 0x8801},
+ {0x0004, 0x8800},
+ {0x000f, 0x8801},
+ {0x0000, 0x8800},
+ {0x0010, 0x8801},
+ {0x0006, 0x8800},
+ {0x0011, 0x8801},
+ {0x0006, 0x8800},
+ {0x0012, 0x8801},
+ {0x0000, 0x8800},
+ {0x0013, 0x8801},
+ {0x0001, 0x8800},
+
+ {0x000a, 0x8700},
+ {0x0000, 0x8702},
+ {0x0000, 0x8703},
+ {0x00c2, 0x8704},
+ {0x0001, 0x870c},
+
+ {0x0044, 0x8600},
+ {0x0002, 0x8606},
+ {0x0064, 0x8607},
+ {0x003a, 0x8601},
+ {0x0008, 0x8602},
+ {0x0044, 0x8600},
+ {0x0018, 0x8617},
+ {0x0008, 0x8618},
+ {0x00a1, 0x8656},
+ {0x0004, 0x865b},
+ {0x0002, 0x865c},
+ {0x0058, 0x865d},
+ {0x0048, 0x865e},
+ {0x0012, 0x8608},
+ {0x002c, 0x8609},
+ {0x0002, 0x860a},
+ {0x002c, 0x860b},
+ {0x00db, 0x860c},
+ {0x00f9, 0x860d},
+ {0x00f1, 0x860e},
+ {0x00e3, 0x860f},
+ {0x002c, 0x8610},
+ {0x006c, 0x8651},
+ {0x0041, 0x8652},
+ {0x0059, 0x8653},
+ {0x0040, 0x8654},
+ {0x00fa, 0x8611},
+ {0x00ff, 0x8612},
+ {0x00f8, 0x8613},
+ {0x0000, 0x8614},
+ {0x0001, 0x863f},
+ {0x0000, 0x8640},
+ {0x0026, 0x8641},
+ {0x0045, 0x8642},
+ {0x0060, 0x8643},
+ {0x0075, 0x8644},
+ {0x0088, 0x8645},
+ {0x009b, 0x8646},
+ {0x00b0, 0x8647},
+ {0x00c5, 0x8648},
+ {0x00d2, 0x8649},
+ {0x00dc, 0x864a},
+ {0x00e5, 0x864b},
+ {0x00eb, 0x864c},
+ {0x00f0, 0x864d},
+ {0x00f6, 0x864e},
+ {0x00fa, 0x864f},
+ {0x00ff, 0x8650},
+ {0x0060, 0x8657},
+ {0x0010, 0x8658},
+ {0x0018, 0x8659},
+ {0x0005, 0x865a},
+ {0x0018, 0x8660},
+ {0x0003, 0x8509},
+ {0x0011, 0x850a},
+ {0x0032, 0x850b},
+ {0x0010, 0x850c},
+ {0x0021, 0x850d},
+ {0x0001, 0x8500},
+ {0x0000, 0x8508},
+ {0x0012, 0x8608},
+ {0x002c, 0x8609},
+ {0x0002, 0x860a},
+ {0x0039, 0x860b},
+ {0x00d0, 0x860c},
+ {0x00f7, 0x860d},
+ {0x00ed, 0x860e},
+ {0x00db, 0x860f},
+ {0x0039, 0x8610},
+ {0x0012, 0x8657},
+ {0x000c, 0x8619},
+ {0x0004, 0x861a},
+ {0x00a1, 0x8656},
+ {0x00c8, 0x8615},
+ {0x0032, 0x8616},
+
+ {0x0030, 0x8112},
+ {0x0020, 0x8112},
+ {0x0020, 0x8112},
+ {0x000f, 0x8402},
+ {0x0000, 0x8403},
+
+ {0x0090, 0x8110},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0001, 0x8114},
+ {0x0003, 0x8114},
+ {0x0080, 0x8804},
+
+ {0x0003, 0x8801},
+ {0x0012, 0x8800},
+ {0x0004, 0x8801},
+ {0x0005, 0x8800},
+ {0x0005, 0x8801},
+ {0x0047, 0x8800},
+ {0x0006, 0x8801},
+ {0x0000, 0x8800},
+ {0x0007, 0x8801},
+ {0x00c0, 0x8800},
+ {0x0008, 0x8801},
+ {0x0003, 0x8800},
+ {0x000a, 0x8700},
+ {0x000e, 0x8801},
+ {0x0004, 0x8800},
+ {0x0005, 0x8801},
+ {0x0047, 0x8800},
+ {0x0006, 0x8801},
+ {0x0000, 0x8800},
+ {0x0007, 0x8801},
+ {0x00c0, 0x8800},
+ {0x0008, 0x8801},
+ {0x0003, 0x8800},
+ {0x0013, 0x8801},
+ {0x0001, 0x8800},
+ {0x0009, 0x8801},
+ {0x0000, 0x8800},
+ {0x000a, 0x8801},
+ {0x0000, 0x8800},
+ {0x000b, 0x8801},
+ {0x0000, 0x8800},
+ {0x000c, 0x8801},
+ {0x0000, 0x8800},
+ {0x000e, 0x8801},
+ {0x0004, 0x8800},
+ {0x000f, 0x8801},
+ {0x0000, 0x8800},
+ {0x0010, 0x8801},
+ {0x0006, 0x8800},
+ {0x0011, 0x8801},
+ {0x0006, 0x8800},
+ {0x0012, 0x8801},
+ {0x0000, 0x8800},
+ {0x0013, 0x8801},
+ {0x0001, 0x8800},
+ {0x000a, 0x8700},
+ {0x0000, 0x8702},
+ {0x0000, 0x8703},
+ {0x00c2, 0x8704},
+ {0x0001, 0x870c},
+ {0x0044, 0x8600},
+ {0x0002, 0x8606},
+ {0x0064, 0x8607},
+ {0x003a, 0x8601},
+ {0x0008, 0x8602},
+ {0x0044, 0x8600},
+ {0x0018, 0x8617},
+ {0x0008, 0x8618},
+ {0x00a1, 0x8656},
+ {0x0004, 0x865b},
+ {0x0002, 0x865c},
+ {0x0058, 0x865d},
+ {0x0048, 0x865e},
+ {0x0012, 0x8608},
+ {0x002c, 0x8609},
+ {0x0002, 0x860a},
+ {0x002c, 0x860b},
+ {0x00db, 0x860c},
+ {0x00f9, 0x860d},
+ {0x00f1, 0x860e},
+ {0x00e3, 0x860f},
+ {0x002c, 0x8610},
+ {0x006c, 0x8651},
+ {0x0041, 0x8652},
+ {0x0059, 0x8653},
+ {0x0040, 0x8654},
+ {0x00fa, 0x8611},
+ {0x00ff, 0x8612},
+ {0x00f8, 0x8613},
+ {0x0000, 0x8614},
+ {0x0001, 0x863f},
+ {0x0000, 0x8640},
+ {0x0026, 0x8641},
+ {0x0045, 0x8642},
+ {0x0060, 0x8643},
+ {0x0075, 0x8644},
+ {0x0088, 0x8645},
+ {0x009b, 0x8646},
+ {0x00b0, 0x8647},
+ {0x00c5, 0x8648},
+ {0x00d2, 0x8649},
+ {0x00dc, 0x864a},
+ {0x00e5, 0x864b},
+ {0x00eb, 0x864c},
+ {0x00f0, 0x864d},
+ {0x00f6, 0x864e},
+ {0x00fa, 0x864f},
+ {0x00ff, 0x8650},
+ {0x0060, 0x8657},
+ {0x0010, 0x8658},
+ {0x0018, 0x8659},
+ {0x0005, 0x865a},
+ {0x0018, 0x8660},
+ {0x0003, 0x8509},
+ {0x0011, 0x850a},
+ {0x0032, 0x850b},
+ {0x0010, 0x850c},
+ {0x0021, 0x850d},
+ {0x0001, 0x8500},
+ {0x0000, 0x8508},
+
+ {0x0012, 0x8608},
+ {0x002c, 0x8609},
+ {0x0002, 0x860a},
+ {0x0039, 0x860b},
+ {0x00d0, 0x860c},
+ {0x00f7, 0x860d},
+ {0x00ed, 0x860e},
+ {0x00db, 0x860f},
+ {0x0039, 0x8610},
+ {0x0012, 0x8657},
+ {0x0064, 0x8619},
/* This line starts it all, it is not needed here */
/* since it has been build into the driver */
/* jfm: don't start now */
-/* 590 * {0x0030, 0x8112}, */
+/* {0x0030, 0x8112}, */
{}
};
@@ -1136,14 +1069,14 @@ static const u16 spca508_vista_init_data[][2] = {
{0x0008, 0x8200}, /* Clear register */
{0x0000, 0x870b}, /* Reset CTL3 */
{0x0020, 0x8112}, /* Video Drop packet enable */
- {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
+ {0x0003, 0x8111}, /* Soft Reset compression, memory, TG & CDSP */
{0x0000, 0x8110}, /* Disable everything */
{0x0000, 0x8114}, /* Software GPIO output data */
{0x0000, 0x8114},
{0x0003, 0x8111},
{0x0000, 0x8111},
- {0x0090, 0x8110}, /* Enable: SSI output, External 2X clock output */
+ {0x0090, 0x8110}, /* Enable: SSI output, External 2X clock output */
{0x0020, 0x8112},
{0x0000, 0x8114},
{0x0001, 0x8114},
@@ -1156,191 +1089,143 @@ static const u16 spca508_vista_init_data[][2] = {
{0x00ba, 0x8804}, /* SSI Slave address */
{0x0010, 0x8802}, /* 93.75kHz SSI Clock Two DataByte */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802}, /* Will write 2 bytes (DATA1+DATA2) */
{0x0020, 0x8801}, /* Register address for SSI read/write */
{0x0044, 0x8805}, /* DATA2 */
{0x0004, 0x8800}, /* DATA1 -> write triggered */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0009, 0x8801},
{0x0042, 0x8805},
{0x0001, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x003c, 0x8801},
{0x0001, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0001, 0x8801},
{0x000a, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0002, 0x8801},
{0x0000, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0003, 0x8801},
{0x0027, 0x8805},
{0x0001, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0004, 0x8801},
{0x0065, 0x8805},
{0x0001, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0005, 0x8801},
{0x0003, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0006, 0x8801},
{0x001c, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0007, 0x8801},
{0x002a, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x000e, 0x8801},
{0x0000, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0028, 0x8801},
{0x002e, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0039, 0x8801},
{0x0013, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x003b, 0x8801},
{0x000c, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0035, 0x8801},
{0x0028, 0x8805},
{0x0000, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
- /* READ { 0, 0x0001, 0x8802 } ->
- 0000: 10 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
+ /* READ { 0x0001, 0x8802 } -> 0000: 10 */
{0x0010, 0x8802},
{0x0009, 0x8801},
{0x0042, 0x8805},
{0x0001, 0x8800},
- /* READ { 0, 0x0001, 0x8803 } ->
- 0000: 00 */
+ /* READ { 0x0001, 0x8803 } -> 0000: 00 */
{0x0050, 0x8703},
{0x0002, 0x8704}, /* External input CKIx1 */
{0x0001, 0x870c}, /* Select CKOx2 output */
{0x009a, 0x8600}, /* Line memory Read Counter (L) */
- {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
+ {0x0001, 0x8606}, /* 1 Line memory Read Counter (H) Result: (d)410 */
{0x0023, 0x8601},
{0x0010, 0x8602},
{0x000a, 0x8603},
- {0x009A, 0x8600},
+ {0x009a, 0x8600},
{0x0001, 0x865b}, /* 1 Horizontal Offset for Valid Pixel(L) */
{0x0003, 0x865c}, /* Vertical offset for valid lines (L) */
{0x0058, 0x865d}, /* Horizontal valid pixels window (L) */
@@ -1356,7 +1241,7 @@ static const u16 spca508_vista_init_data[][2] = {
{0x0005, 0x860a}, /* ... */
{0x0025, 0x860b},
{0x00e1, 0x860c},
- {0x00fa, 0x860D},
+ {0x00fa, 0x860d},
{0x00f4, 0x860e},
{0x00e8, 0x860f},
{0x0025, 0x8610}, /* A33 Coef. */
@@ -1371,11 +1256,12 @@ static const u16 spca508_vista_init_data[][2] = {
{0x0040, 0x8654}, /* Gb gain for white balance (L) */
{0x0001, 0x863f}, /* Enable fixed gamma correction */
- {0x00a1, 0x8656}, /* Size - Window1: 256x256, Window2: 128x128 */
- /* UV division: UV no change, Enable New edge enhancement */
+ {0x00a1, 0x8656}, /* Size - Window1: 256x256, Window2: 128x128,
+ * UV division: UV no change,
+ * Enable New edge enhancement */
{0x0018, 0x8657}, /* Edge gain high threshold */
{0x0020, 0x8658}, /* Edge gain low threshold */
- {0x000A, 0x8659}, /* Edge bandwidth high threshold */
+ {0x000a, 0x8659}, /* Edge bandwidth high threshold */
{0x0005, 0x865a}, /* Edge bandwidth low threshold */
{0x0064, 0x8607}, /* UV filter enable */
@@ -1411,29 +1297,20 @@ static const u16 spca508_vista_init_data[][2] = {
{0x0000, 0x86b4},
{0x001e, 0x8660},
- /* READ { 0, 0x0000, 0x8608 } ->
- 0000: 13 */
- /* READ { 0, 0x0000, 0x8609 } ->
- 0000: 28 */
- /* READ { 0, 0x0000, 0x8610 } ->
- 0000: 05 */
- /* READ { 0, 0x0000, 0x8611 } ->
- 0000: 25 */
- /* READ { 0, 0x0000, 0x8612 } ->
- 0000: e1 */
- /* READ { 0, 0x0000, 0x8613 } ->
- 0000: fa */
- /* READ { 0, 0x0000, 0x8614 } ->
- 0000: f4 */
- /* READ { 0, 0x0000, 0x8615 } ->
- 0000: e8 */
- /* READ { 0, 0x0000, 0x8616 } ->
- 0000: 25 */
+ /* READ { 0x0000, 0x8608 } -> 0000: 13 */
+ /* READ { 0x0000, 0x8609 } -> 0000: 28 */
+ /* READ { 0x0000, 0x8610 } -> 0000: 05 */
+ /* READ { 0x0000, 0x8611 } -> 0000: 25 */
+ /* READ { 0x0000, 0x8612 } -> 0000: e1 */
+ /* READ { 0x0000, 0x8613 } -> 0000: fa */
+ /* READ { 0x0000, 0x8614 } -> 0000: f4 */
+ /* READ { 0x0000, 0x8615 } -> 0000: e8 */
+ /* READ { 0x0000, 0x8616 } -> 0000: 25 */
{}
};
static int reg_write(struct usb_device *dev,
- __u16 index, __u16 value)
+ u16 index, u16 value)
{
int ret;
@@ -1452,7 +1329,7 @@ static int reg_write(struct usb_device *dev,
/* read 1 byte */
/* returns: negative is error, pos or zero is data */
static int reg_read(struct gspca_dev *gspca_dev,
- __u16 index) /* wIndex */
+ u16 index) /* wIndex */
{
int ret;
@@ -1474,16 +1351,16 @@ static int reg_read(struct gspca_dev *gspca_dev,
}
static int write_vector(struct gspca_dev *gspca_dev,
- const u16 data[][2])
+ const u16 (*data)[2])
{
struct usb_device *dev = gspca_dev->dev;
- int ret, i = 0;
+ int ret;
- while (data[i][1] != 0) {
- ret = reg_write(dev, data[i][1], data[i][0]);
+ while ((*data)[1] != 0) {
+ ret = reg_write(dev, (*data)[1], (*data)[0]);
if (ret < 0)
return ret;
- i++;
+ data++;
}
return 0;
}
@@ -1495,6 +1372,15 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
int data1, data2;
+ const u16 (*init_data)[2];
+ static const u16 (*(init_data_tb[]))[2] = {
+ spca508_vista_init_data, /* CreativeVista 0 */
+ spca508_sightcam_init_data, /* HamaUSBSightcam 1 */
+ spca508_sightcam2_init_data, /* HamaUSBSightcam2 2 */
+ spca508cs110_init_data, /* IntelEasyPCCamera 3 */
+ spca508cs110_init_data, /* MicroInnovationIC200 4 */
+ spca508_init_data, /* ViewQuestVQ110 5 */
+ };
/* Read from global register the USB product and vendor IDs, just to
* prove that we can communicate with the device. This works, which
@@ -1518,37 +1404,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->subtype = id->driver_info;
sd->brightness = BRIGHTNESS_DEF;
- switch (sd->subtype) {
- case ViewQuestVQ110:
- if (write_vector(gspca_dev, spca508_init_data))
- return -1;
- break;
- default:
-/* case MicroInnovationIC200: */
-/* case IntelEasyPCCamera: */
- if (write_vector(gspca_dev, spca508cs110_init_data))
- return -1;
- break;
- case HamaUSBSightcam:
- if (write_vector(gspca_dev, spca508_sightcam_init_data))
- return -1;
- break;
- case HamaUSBSightcam2:
- if (write_vector(gspca_dev, spca508_sightcam2_init_data))
- return -1;
- break;
- case CreativeVista:
- if (write_vector(gspca_dev, spca508_vista_init_data))
- return -1;
- break;
- }
- return 0; /* success */
+ init_data = init_data_tb[sd->subtype];
+ return write_vector(gspca_dev, init_data);
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
-/* write_vector(gspca_dev, spca508_open_data); */
return 0;
}
@@ -1556,7 +1418,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
int mode;
- mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
reg_write(gspca_dev->dev, 0x8500, mode);
switch (mode) {
case 0:
@@ -1581,7 +1443,7 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
- __u8 *data, /* isoc packet */
+ u8 *data, /* isoc packet */
int len) /* iso packet length */
{
switch (data[0]) {
@@ -1594,7 +1456,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data, len);
break;
case 0xff: /* drop */
-/* gspca_dev->last_packet_type = DISCARD_PACKET; */
break;
default:
data += 1;
@@ -1608,7 +1469,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 brightness = sd->brightness;
+ u8 brightness = sd->brightness;
/* MX seem contrast */
reg_write(gspca_dev->dev, 0x8651, brightness);
diff --git a/linux/drivers/media/video/gspca/spca561.c b/linux/drivers/media/video/gspca/spca561.c
index c8dd036a6..cb3313e19 100644
--- a/linux/drivers/media/video/gspca/spca561.c
+++ b/linux/drivers/media/video/gspca/spca561.c
@@ -34,8 +34,8 @@ struct sd {
__u16 exposure; /* rev12a only */
#define EXPOSURE_MIN 1
-#define EXPOSURE_DEF 200
-#define EXPOSURE_MAX (4095 - 900) /* see set_exposure */
+#define EXPOSURE_DEF 700 /* == 10 fps */
+#define EXPOSURE_MAX (2047 + 325) /* see setexposure */
__u8 contrast; /* rev72a only */
#define CONTRAST_MIN 0x00
@@ -48,9 +48,9 @@ struct sd {
#define BRIGHTNESS_MAX 0x3f
__u8 white;
-#define WHITE_MIN 1
-#define WHITE_DEF 0x40
-#define WHITE_MAX 0x7f
+#define HUE_MIN 1
+#define HUE_DEF 0x40
+#define HUE_MAX 0x7f
__u8 autogain;
#define AUTOGAIN_MIN 0
@@ -58,9 +58,9 @@ struct sd {
#define AUTOGAIN_MAX 1
__u8 gain; /* rev12a only */
-#define GAIN_MIN 0x0
-#define GAIN_DEF 0x24
-#define GAIN_MAX 0x24
+#define GAIN_MIN 0
+#define GAIN_DEF 63
+#define GAIN_MAX 255
#define EXPO12A_DEF 3
__u8 expo12a; /* expo/gain? for rev 12a */
@@ -492,7 +492,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
sd->brightness = BRIGHTNESS_DEF;
sd->contrast = CONTRAST_DEF;
- sd->white = WHITE_DEF;
+ sd->white = HUE_DEF;
sd->exposure = EXPOSURE_DEF;
sd->autogain = AUTOGAIN_DEF;
sd->gain = GAIN_DEF;
@@ -580,8 +580,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int expo;
- int clock_divider;
+ int i, expo = 0;
/* Register 0x8309 controls exposure for the spca561,
the basic exposure setting goes from 1-2047, where 1 is completely
@@ -595,16 +594,22 @@ static void setexposure(struct gspca_dev *gspca_dev)
configure a divider for the base framerate which us used at the
exposure setting of 1-300. These bits configure the base framerate
according to the following formula: fps = 60 / (value + 2) */
- if (sd->exposure < 2048) {
- expo = sd->exposure;
- clock_divider = 0;
- } else {
- /* Add 900 to make the 0 setting of the second part of the
- exposure equal to the 2047 setting of the first part. */
- expo = (sd->exposure - 2048) + 900;
- clock_divider = 3;
+
+ /* We choose to use the high bits setting the fixed framerate divisor
+ asap, as setting high basic exposure setting without the fixed
+ divider in combination with high gains makes the cam stop */
+ int table[] = { 0, 450, 550, 625, EXPOSURE_MAX };
+
+ for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
+ if (sd->exposure <= table[i + 1]) {
+ expo = sd->exposure - table[i];
+ if (i)
+ expo += 300;
+ expo |= i << 11;
+ break;
+ }
}
- expo |= clock_divider << 11;
+
gspca_dev->usb_buf[0] = expo;
gspca_dev->usb_buf[1] = expo >> 8;
reg_w_buf(gspca_dev, 0x8309, 2);
@@ -615,7 +620,16 @@ static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- gspca_dev->usb_buf[0] = sd->gain;
+ /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the
+ sensitivity when set, so 31 + one of them set == 63, and 15
+ with both of them set == 63 */
+ if (sd->gain < 64)
+ gspca_dev->usb_buf[0] = sd->gain;
+ else if (sd->gain < 128)
+ gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40;
+ else
+ gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xC0;
+
gspca_dev->usb_buf[1] = 0;
reg_w_buf(gspca_dev, 0x8335, 2);
}
@@ -660,8 +674,7 @@ static int sd_start_12a(struct gspca_dev *gspca_dev)
reg_w_buf(gspca_dev, 0x8391, 8);
reg_w_buf(gspca_dev, 0x8390, 8);
setwhite(gspca_dev);
- setautogain(gspca_dev);
-/* setgain(gspca_dev); */
+ setgain(gspca_dev);
setexposure(gspca_dev);
return 0;
}
@@ -793,18 +806,6 @@ static void do_autogain(struct gspca_dev *gspca_dev)
i2c_write(gspca_dev, expotimes | pixelclk, 0x09);
}
break;
- case Rev012A:
- reg_r(gspca_dev, 0x8330, 2);
- if (gspca_dev->usb_buf[1] > 0x08) {
- 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) {
- gspca_dev->usb_buf[0] = --sd->expo12a;
- gspca_dev->usb_buf[1] = 0;
- reg_w_buf(gspca_dev, 0x8339, 2);
- }
- break;
}
}
@@ -959,13 +960,13 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
static struct ctrl sd_ctrls_12a[] = {
{
{
- .id = V4L2_CID_DO_WHITE_BALANCE,
+ .id = V4L2_CID_HUE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "White Balance",
- .minimum = WHITE_MIN,
- .maximum = WHITE_MAX,
+ .name = "Hue",
+ .minimum = HUE_MIN,
+ .maximum = HUE_MAX,
.step = 1,
- .default_value = WHITE_DEF,
+ .default_value = HUE_DEF,
},
.set = sd_setwhite,
.get = sd_getwhite,
@@ -985,19 +986,6 @@ static struct ctrl sd_ctrls_12a[] = {
},
{
{
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Gain",
- .minimum = AUTOGAIN_MIN,
- .maximum = AUTOGAIN_MAX,
- .step = 1,
- .default_value = AUTOGAIN_DEF,
- },
- .set = sd_setautogain,
- .get = sd_getautogain,
- },
- {
- {
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
@@ -1014,13 +1002,13 @@ static struct ctrl sd_ctrls_12a[] = {
static struct ctrl sd_ctrls_72a[] = {
{
{
- .id = V4L2_CID_DO_WHITE_BALANCE,
+ .id = V4L2_CID_HUE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "White Balance",
- .minimum = WHITE_MIN,
- .maximum = WHITE_MAX,
+ .name = "Hue",
+ .minimum = HUE_MIN,
+ .maximum = HUE_MAX,
.step = 1,
- .default_value = WHITE_DEF,
+ .default_value = HUE_DEF,
},
.set = sd_setwhite,
.get = sd_getwhite,
@@ -1077,7 +1065,6 @@ static const struct sd_desc sd_desc_12a = {
.stopN = sd_stopN,
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
-/* .dq_callback = do_autogain, * fixme */
};
static const struct sd_desc sd_desc_72a = {
.name = MODULE_NAME,
diff --git a/linux/drivers/media/video/gspca/sq905.c b/linux/drivers/media/video/gspca/sq905.c
index da60eea51..715a68f01 100644
--- a/linux/drivers/media/video/gspca/sq905.c
+++ b/linux/drivers/media/video/gspca/sq905.c
@@ -82,8 +82,6 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- const struct v4l2_pix_format *cap_mode;
-
/*
* Driver stuff
*/
@@ -218,6 +216,7 @@ static void sq905_dostream(struct work_struct *work)
int header_read; /* true if we have already read the frame header. */
int discarding; /* true if we failed to get space for frame. */
int packet_type;
+ int frame_sz;
int ret;
u8 *data;
u8 *buffer;
@@ -229,6 +228,9 @@ static void sq905_dostream(struct work_struct *work)
goto quit_stream;
}
+ frame_sz = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].sizeimage
+ + FRAME_HEADER_LEN;
+
while (gspca_dev->present && gspca_dev->streaming) {
/* Need a short delay to ensure streaming flag was set by
* gspca and to make sure gspca can grab the mutex. */
@@ -237,7 +239,7 @@ static void sq905_dostream(struct work_struct *work)
/* request some data and then read it until we have
* a complete frame. */
- bytes_left = dev->cap_mode->sizeimage + FRAME_HEADER_LEN;
+ bytes_left = frame_sz;
header_read = 0;
discarding = 0;
@@ -270,13 +272,14 @@ static void sq905_dostream(struct work_struct *work)
}
frame = gspca_get_i_frame(gspca_dev);
if (frame && !discarding) {
- gspca_frame_add(gspca_dev, packet_type,
+ frame = gspca_frame_add(gspca_dev, packet_type,
frame, data, data_len);
/* If entire frame fits in one packet we still
need to add a LAST_PACKET */
- if ((packet_type == FIRST_PACKET) &&
- (bytes_left == 0))
- gspca_frame_add(gspca_dev, LAST_PACKET,
+ if (packet_type == FIRST_PACKET &&
+ bytes_left == 0)
+ frame = gspca_frame_add(gspca_dev,
+ LAST_PACKET,
frame, data, 0);
} else {
discarding = 1;
@@ -306,6 +309,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct sd *dev = (struct sd *) gspca_dev;
/* We don't use the buffer gspca allocates so make it small. */
+ cam->bulk = 1;
cam->bulk_size = 64;
INIT_WORK(&dev->work_struct, sq905_dostream);
@@ -357,6 +361,12 @@ static int sd_init(struct gspca_dev *gspca_dev)
gspca_dev->cam.nmodes = ARRAY_SIZE(sq905_mode);
if (!(ident & SQ905_HIRES_MASK))
gspca_dev->cam.nmodes--;
+
+ if (ident & SQ905_ORIENTATION_MASK)
+ gspca_dev->cam.input_flags = V4L2_IN_ST_VFLIP;
+ else
+ gspca_dev->cam.input_flags = V4L2_IN_ST_VFLIP |
+ V4L2_IN_ST_HFLIP;
return 0;
}
@@ -366,21 +376,18 @@ static int sd_start(struct gspca_dev *gspca_dev)
struct sd *dev = (struct sd *) gspca_dev;
int ret;
- /* Set capture mode based on selected resolution. */
- dev->cap_mode = gspca_dev->cam.cam_mode;
/* "Open the shutter" and set size, to start capture */
- switch (gspca_dev->width) {
- case 640:
+ switch (gspca_dev->curr_mode) {
+ default:
+/* case 2: */
PDEBUG(D_STREAM, "Start streaming at high resolution");
- dev->cap_mode += 2;
ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_HIGH);
break;
- case 320:
+ case 1:
PDEBUG(D_STREAM, "Start streaming at medium resolution");
- dev->cap_mode++;
ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_MED);
break;
- default:
+ case 0:
PDEBUG(D_STREAM, "Start streaming at low resolution");
ret = sq905_command(&dev->gspca_dev, SQ905_CAPTURE_LOW);
}
diff --git a/linux/drivers/media/video/gspca/sq905c.c b/linux/drivers/media/video/gspca/sq905c.c
new file mode 100644
index 000000000..916892505
--- /dev/null
+++ b/linux/drivers/media/video/gspca/sq905c.c
@@ -0,0 +1,329 @@
+/*
+ * SQ905C subdriver
+ *
+ * Copyright (C) 2009 Theodore Kilgore
+ *
+ * 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
+ * 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
+ */
+
+/*
+ *
+ * This driver uses work done in
+ * libgphoto2/camlibs/digigr8, Copyright (C) Theodore Kilgore.
+ *
+ * This driver has also used as a base the sq905c driver
+ * and may contain code fragments from it.
+ */
+
+#define MODULE_NAME "sq905c"
+
+#include <linux/workqueue.h>
+#include "gspca.h"
+
+MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
+MODULE_DESCRIPTION("GSPCA/SQ905C USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeouts, in ms */
+#define SQ905C_CMD_TIMEOUT 500
+#define SQ905C_DATA_TIMEOUT 1000
+
+/* Maximum transfer size to use. */
+#define SQ905C_MAX_TRANSFER 0x8000
+
+#define FRAME_HEADER_LEN 0x50
+
+/* Commands. These go in the "value" slot. */
+#define SQ905C_CLEAR 0xa0 /* clear everything */
+#define SQ905C_CAPTURE_LOW 0xa040 /* Starts capture at 160x120 */
+#define SQ905C_CAPTURE_MED 0x1440 /* Starts capture at 320x240 */
+#define SQ905C_CAPTURE_HI 0x2840 /* Starts capture at 320x240 */
+
+/* For capture, this must go in the "index" slot. */
+#define SQ905C_CAPTURE_INDEX 0x110f
+
+/* Structure to hold all of our device specific stuff */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ const struct v4l2_pix_format *cap_mode;
+ /* Driver stuff */
+ struct work_struct work_struct;
+ struct workqueue_struct *work_thread;
+};
+
+/*
+ * Most of these cameras will do 640x480 and 320x240. 160x120 works
+ * in theory but gives very poor output. Therefore, not supported.
+ * The 0x2770:0x9050 cameras have max resolution of 320x240.
+ */
+static struct v4l2_pix_format sq905c_mode[] = {
+ { 320, 240, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ { 640, 480, V4L2_PIX_FMT_SQ905C, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0}
+};
+
+/* Send a command to the camera. */
+static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index)
+{
+ int ret;
+
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ USB_REQ_SYNCH_FRAME, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ command, index, NULL, 0,
+ SQ905C_CMD_TIMEOUT);
+ if (ret < 0) {
+ PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
+ __func__, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+/* This function is called as a workqueue function and runs whenever the camera
+ * is streaming data. Because it is a workqueue function it is allowed to sleep
+ * so we can use synchronous USB calls. To avoid possible collisions with other
+ * threads attempting to use the camera's USB interface the gspca usb_lock is
+ * used when performing the one USB control operation inside the workqueue,
+ * which tells the camera to close the stream. In practice the only thing
+ * which needs to be protected against is the usb_set_interface call that
+ * gspca makes during stream_off. Otherwise the camera doesn't provide any
+ * controls that the user could try to change.
+ */
+static void sq905c_dostream(struct work_struct *work)
+{
+ struct sd *dev = container_of(work, struct sd, work_struct);
+ struct gspca_dev *gspca_dev = &dev->gspca_dev;
+ struct gspca_frame *frame;
+ int bytes_left; /* bytes remaining in current frame. */
+ int data_len; /* size to use for the next read. */
+ int act_len;
+ int discarding = 0; /* true if we failed to get space for frame. */
+ int packet_type;
+ int ret;
+ u8 *buffer;
+
+ buffer = kmalloc(SQ905C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
+ if (!buffer) {
+ PDEBUG(D_ERR, "Couldn't allocate USB buffer");
+ goto quit_stream;
+ }
+
+ while (gspca_dev->present && gspca_dev->streaming) {
+ if (!gspca_dev->present)
+ goto quit_stream;
+ /* Request the header, which tells the size to download */
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x81),
+ buffer, FRAME_HEADER_LEN, &act_len,
+ SQ905C_DATA_TIMEOUT);
+ PDEBUG(D_STREAM,
+ "Got %d bytes out of %d for header",
+ act_len, FRAME_HEADER_LEN);
+ if (ret < 0 || act_len < FRAME_HEADER_LEN)
+ goto quit_stream;
+ /* size is read from 4 bytes starting 0x40, little endian */
+ bytes_left = buffer[0x40]|(buffer[0x41]<<8)|(buffer[0x42]<<16)
+ |(buffer[0x43]<<24);
+ PDEBUG(D_STREAM, "bytes_left = 0x%x", bytes_left);
+ /* We keep the header. It has other information, too. */
+ packet_type = FIRST_PACKET;
+ frame = gspca_get_i_frame(gspca_dev);
+ if (frame && !discarding) {
+ gspca_frame_add(gspca_dev, packet_type,
+ frame, buffer, FRAME_HEADER_LEN);
+ } else
+ discarding = 1;
+ while (bytes_left > 0) {
+ data_len = bytes_left > SQ905C_MAX_TRANSFER ?
+ SQ905C_MAX_TRANSFER : bytes_left;
+ if (!gspca_dev->present)
+ goto quit_stream;
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x81),
+ buffer, data_len, &act_len,
+ SQ905C_DATA_TIMEOUT);
+ if (ret < 0 || act_len < data_len)
+ goto quit_stream;
+ PDEBUG(D_STREAM,
+ "Got %d bytes out of %d for frame",
+ data_len, bytes_left);
+ bytes_left -= data_len;
+ if (bytes_left == 0)
+ packet_type = LAST_PACKET;
+ else
+ packet_type = INTER_PACKET;
+ frame = gspca_get_i_frame(gspca_dev);
+ if (frame && !discarding)
+ gspca_frame_add(gspca_dev, packet_type,
+ frame, buffer, data_len);
+ else
+ discarding = 1;
+ }
+ }
+quit_stream:
+ mutex_lock(&gspca_dev->usb_lock);
+ if (gspca_dev->present)
+ sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
+ mutex_unlock(&gspca_dev->usb_lock);
+ kfree(buffer);
+}
+
+/* This function is called at probe time just before sd_init */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct cam *cam = &gspca_dev->cam;
+ struct sd *dev = (struct sd *) gspca_dev;
+
+ PDEBUG(D_PROBE,
+ "SQ9050 camera detected"
+ " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct);
+ cam->cam_mode = sq905c_mode;
+ cam->nmodes = 2;
+ if (id->idProduct == 0x9050)
+ cam->nmodes = 1;
+ /* We don't use the buffer gspca allocates so make it small. */
+ cam->bulk_size = 32;
+ cam->bulk = 1;
+ INIT_WORK(&dev->work_struct, sq905c_dostream);
+ return 0;
+}
+
+/* called on streamoff with alt==0 and on disconnect */
+/* the usb_lock is held at entry - restore on exit */
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *dev = (struct sd *) gspca_dev;
+
+ /* wait for the work queue to terminate */
+ mutex_unlock(&gspca_dev->usb_lock);
+ /* This waits for sq905c_dostream to finish */
+ destroy_workqueue(dev->work_thread);
+ dev->work_thread = NULL;
+ mutex_lock(&gspca_dev->usb_lock);
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ int ret;
+
+ /* connect to the camera and reset it. */
+ ret = sq905c_command(gspca_dev, SQ905C_CLEAR, 0);
+ return ret;
+}
+
+/* Set up for getting frames. */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *dev = (struct sd *) gspca_dev;
+ int ret;
+
+ dev->cap_mode = gspca_dev->cam.cam_mode;
+ /* "Open the shutter" and set size, to start capture */
+ switch (gspca_dev->width) {
+ case 640:
+ PDEBUG(D_STREAM, "Start streaming at high resolution");
+ dev->cap_mode++;
+ ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_HI,
+ SQ905C_CAPTURE_INDEX);
+ break;
+ default: /* 320 */
+ PDEBUG(D_STREAM, "Start streaming at medium resolution");
+ ret = sq905c_command(gspca_dev, SQ905C_CAPTURE_MED,
+ SQ905C_CAPTURE_INDEX);
+ }
+
+ if (ret < 0) {
+ PDEBUG(D_ERR, "Start streaming command failed");
+ return ret;
+ }
+ /* Start the workqueue function to do the streaming */
+ dev->work_thread = create_singlethread_workqueue(MODULE_NAME);
+ queue_work(dev->work_thread, &dev->work_struct);
+
+ return 0;
+}
+
+/* Table of supported USB devices */
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x2770, 0x905c)},
+ {USB_DEVICE(0x2770, 0x9050)},
+ {USB_DEVICE(0x2770, 0x913d)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stop0 = sd_stop0,
+};
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id,
+ &sd_desc,
+ sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ int ret;
+
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ 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);
diff --git a/linux/drivers/media/video/gspca/stk014.c b/linux/drivers/media/video/gspca/stk014.c
index d1d54edd8..f25be20cf 100644
--- a/linux/drivers/media/video/gspca/stk014.c
+++ b/linux/drivers/media/video/gspca/stk014.c
@@ -21,8 +21,6 @@
#define MODULE_NAME "stk014"
#include "gspca.h"
-#define QUANT_VAL 7 /* quantization table */
- /* <= 4 KO - 7: good (enough!) */
#include "jpeg.h"
MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
@@ -37,6 +35,12 @@ struct sd {
unsigned char contrast;
unsigned char colors;
unsigned char lightfreq;
+ u8 quality;
+#define QUALITY_MIN 60
+#define QUALITY_MAX 95
+#define QUALITY_DEF 80
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -300,6 +304,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->contrast = CONTRAST_DEF;
sd->colors = COLOR_DEF;
sd->lightfreq = FREQ_DEF;
+ sd->quality = QUALITY_DEF;
return 0;
}
@@ -323,8 +328,15 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* -- start the camera -- */
static int sd_start(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
int ret, value;
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x22); /* JPEG 411 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
/* work on alternate 1 */
usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
@@ -396,11 +408,19 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
PDEBUG(D_STREAM, "camera stopped");
}
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ kfree(sd->jpeg_hdr);
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
static unsigned char ffd9[] = {0xff, 0xd9};
/* a frame starts with:
@@ -417,7 +437,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
ffd9, 2);
/* put the JPEG 411 header */
- jpeg_put_header(gspca_dev, frame, 0x22);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
/* beginning of the frame */
#define STKHDRSZ 12
@@ -517,6 +538,34 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -526,8 +575,11 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
index 69c77c932..11a0c002f 100644
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
@@ -80,12 +80,26 @@ static const struct ctrl vv6410_ctrl[] = {
.minimum = 0,
.maximum = 15,
.step = 1,
- .default_value = 0
+ .default_value = 10
},
.set = vv6410_set_analog_gain,
.get = vv6410_get_analog_gain
+ },
+#define EXPOSURE_IDX 3
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0,
+ .maximum = 32768,
+ .step = 1,
+ .default_value = 20000
+ },
+ .set = vv6410_set_exposure,
+ .get = vv6410_get_exposure
}
-};
+ };
static int vv6410_probe(struct sd *sd)
{
@@ -121,6 +135,7 @@ static int vv6410_probe(struct sd *sd)
static int vv6410_init(struct sd *sd)
{
int err = 0, i;
+ s32 *sensor_settings = sd->sensor_priv;
for (i = 0; i < ARRAY_SIZE(stv_bridge_init); i++) {
/* if NULL then len contains single value */
@@ -142,6 +157,16 @@ static int vv6410_init(struct sd *sd)
err = stv06xx_write_sensor_bytes(sd, (u8 *) vv6410_sensor_init,
ARRAY_SIZE(vv6410_sensor_init));
+ if (err < 0)
+ return err;
+
+ err = vv6410_set_exposure(&sd->gspca_dev,
+ sensor_settings[EXPOSURE_IDX]);
+ if (err < 0)
+ return err;
+
+ err = vv6410_set_analog_gain(&sd->gspca_dev,
+ sensor_settings[GAIN_IDX]);
return (err < 0) ? err : 0;
}
@@ -318,3 +343,50 @@ static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val)
return (err < 0) ? err : 0;
}
+
+static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+
+ *val = sensor_settings[EXPOSURE_IDX];
+
+ PDEBUG(D_V4L2, "Read exposure %d", *val);
+
+ return 0;
+}
+
+static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ int err;
+ struct sd *sd = (struct sd *) gspca_dev;
+ s32 *sensor_settings = sd->sensor_priv;
+ unsigned int fine, coarse;
+
+ sensor_settings[EXPOSURE_IDX] = val;
+
+ val = (val * val >> 14) + val / 4;
+
+ fine = val % VV6410_CIF_LINELENGTH;
+ coarse = min(512, val / VV6410_CIF_LINELENGTH);
+
+ PDEBUG(D_V4L2, "Set coarse exposure to %d, fine expsure to %d",
+ coarse, fine);
+
+ err = stv06xx_write_sensor(sd, VV6410_FINEH, fine >> 8);
+ if (err < 0)
+ goto out;
+
+ err = stv06xx_write_sensor(sd, VV6410_FINEL, fine & 0xff);
+ if (err < 0)
+ goto out;
+
+ err = stv06xx_write_sensor(sd, VV6410_COARSEH, coarse >> 8);
+ if (err < 0)
+ goto out;
+
+ err = stv06xx_write_sensor(sd, VV6410_COARSEL, coarse & 0xff);
+
+out:
+ return err;
+}
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
index 95ac55891..487d40555 100644
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
@@ -173,6 +173,8 @@
#define VV6410_SUBSAMPLE 0x01
#define VV6410_CROP_TO_QVGA 0x02
+#define VV6410_CIF_LINELENGTH 415
+
static int vv6410_probe(struct sd *sd);
static int vv6410_start(struct sd *sd);
static int vv6410_init(struct sd *sd);
@@ -187,6 +189,8 @@ static int vv6410_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
static int vv6410_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
static int vv6410_get_analog_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int vv6410_set_analog_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int vv6410_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int vv6410_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
.name = "ST VV6410",
@@ -242,12 +246,6 @@ static const u8 vv6410_sensor_init[][2] = {
/* 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 */
diff --git a/linux/drivers/media/video/gspca/sunplus.c b/linux/drivers/media/video/gspca/sunplus.c
index fba6f98d1..16bc65dc7 100644
--- a/linux/drivers/media/video/gspca/sunplus.c
+++ b/linux/drivers/media/video/gspca/sunplus.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "sunplus"
#include "gspca.h"
-#define QUANT_VAL 5 /* quantization table */
#include "jpeg.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
@@ -33,13 +32,14 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u8 packet[ISO_MAX_SIZE + 128];
- /* !! no more than 128 ff in an ISO packet */
-
unsigned char brightness;
unsigned char contrast;
unsigned char colors;
unsigned char autogain;
+ u8 quality;
+#define QUALITY_MIN 70
+#define QUALITY_MAX 95
+#define QUALITY_DEF 85
char bridge;
#define BRIDGE_SPCA504 0
@@ -52,6 +52,8 @@ struct sd {
#define LogitechClickSmart420 2
#define LogitechClickSmart820 3
#define MegapixV4 4
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -883,6 +885,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->brightness = sd_ctrls[SD_BRIGHTNESS].qctrl.default_value;
sd->contrast = sd_ctrls[SD_CONTRAST].qctrl.default_value;
sd->colors = sd_ctrls[SD_COLOR].qctrl.default_value;
+ sd->quality = QUALITY_DEF;
return 0;
}
@@ -999,6 +1002,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
__u8 i;
__u8 info[6];
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x22); /* JPEG 411 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
if (sd->bridge == BRIDGE_SPCA504B)
spca504B_setQtable(gspca_dev);
spca504B_SetSizeType(gspca_dev);
@@ -1108,6 +1117,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
}
}
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ kfree(sd->jpeg_hdr);
+}
+
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct gspca_frame *frame, /* target */
__u8 *data, /* isoc packet */
@@ -1115,7 +1131,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
int i, sof = 0;
- unsigned char *s, *d;
static unsigned char ffd9[] = {0xff, 0xd9};
/* frames are jpeg 4.1.1 without 0xff escape */
@@ -1184,26 +1199,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
ffd9, 2);
/* put the JPEG header in the new frame */
- jpeg_put_header(gspca_dev, frame, 0x22);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
}
/* add 0x00 after 0xff */
- for (i = len; --i >= 0; )
- if (data[i] == 0xff)
- break;
- if (i < 0) { /* no 0xff */
- gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
- return;
- }
- s = data;
- d = sd->packet;
- for (i = 0; i < len; i++) {
- *d++ = *s++;
- if (s[-1] == 0xff)
- *d++ = 0x00;
- }
- gspca_frame_add(gspca_dev, INTER_PACKET, frame,
- sd->packet, d - sd->packet);
+ i = 0;
+ do {
+ if (data[i] == 0xff) {
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame,
+ data, i + 1);
+ len -= i;
+ data += i;
+ *data = 0x00;
+ i = 0;
+ }
+ i++;
+ } while (i < len);
+ gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
static void setbrightness(struct gspca_dev *gspca_dev)
@@ -1333,6 +1346,34 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -1342,7 +1383,10 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
diff --git a/linux/drivers/media/video/gspca/t613.c b/linux/drivers/media/video/gspca/t613.c
index f60a4c21a..1b58b65fb 100644
--- a/linux/drivers/media/video/gspca/t613.c
+++ b/linux/drivers/media/video/gspca/t613.c
@@ -495,7 +495,7 @@ static void om6802_sensor_init(struct gspca_dev *gspca_dev)
};
reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
- msleep(5);
+ msleep(100);
i = 4;
while (--i > 0) {
byte = reg_r(gspca_dev, 0x0060);
@@ -639,7 +639,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
u16 reg80, reg8e;
static const u8 read_indexs[] =
- { 0x06, 0x07, 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
+ { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
static const u8 n1[] =
{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
@@ -679,7 +679,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
sensor_id = (reg_r(gspca_dev, 0x06) << 8)
| reg_r(gspca_dev, 0x07);
- switch (sensor_id) {
+ switch (sensor_id & 0xff0f) {
case 0x0801:
PDEBUG(D_PROBE, "sensor tas5130a");
sd->sensor = SENSOR_TAS5130A;
@@ -697,7 +697,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
return -EINVAL;
}
- if (sd->sensor != SENSOR_OTHER) {
+ if (sd->sensor == SENSOR_OM6802) {
reg_w_buf(gspca_dev, n1, sizeof n1);
i = 5;
while (--i >= 0) {
diff --git a/linux/drivers/media/video/gspca/vc032x.c b/linux/drivers/media/video/gspca/vc032x.c
index f1c149476..a29c85cac 100644
--- a/linux/drivers/media/video/gspca/vc032x.c
+++ b/linux/drivers/media/video/gspca/vc032x.c
@@ -37,18 +37,21 @@ struct sd {
__u8 lightfreq;
__u8 sharpness;
+ u8 image_offset;
+
char bridge;
#define BRIDGE_VC0321 0
#define BRIDGE_VC0323 1
- char sensor;
+ u8 sensor;
#define SENSOR_HV7131R 0
#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
+#define SENSOR_MI1310_SOC 2
+#define SENSOR_MI1320 3
+#define SENSOR_MI1320_SOC 4
+#define SENSOR_OV7660 5
+#define SENSOR_OV7670 6
+#define SENSOR_PO1200 7
+#define SENSOR_PO3130NC 8
};
/* V4L2 controls supported by the driver */
@@ -149,13 +152,50 @@ static const struct v4l2_pix_format vc0323_mode[] = {
.sizeimage = 640 * 480 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 0},
- {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi1310_soc only */
+ {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, /* mi13x0_soc only */
.bytesperline = 1280,
.sizeimage = 1280 * 1024 * 1 / 4 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
.priv = 2},
};
-
+static const struct v4l2_pix_format bi_mode[] = {
+#if 0 /* JPEG vc0323 */
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 5},
+#endif
+ {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 2},
+#if 0 /* JPEG vc0323 */
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 4},
+#endif
+ {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+#if 0 /* JPEG vc0323 */
+ {1280, 1024, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 1280,
+ .sizeimage = 1280 * 1024 * 1 / 4 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+#endif
+ {1280, 1024, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
+ .bytesperline = 1280,
+ .sizeimage = 1280 * 1024 * 2,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
static const struct v4l2_pix_format svga_mode[] = {
{800, 600, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 800,
@@ -891,6 +931,728 @@ static const __u8 mi1320_initQVGA_data[][4] = {
{}
};
+static const u8 mi1320_soc_InitVGA[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x07, 0x00, 0xe0, 0xbb},
+ {0x08, 0x00, 0x0b, 0xbb},
+ {0x21, 0x00, 0x0c, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+#if 0 /* JPEG vc0323 */
+static const u8 mi1320_soc_InitVGA_JPG[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x07, 0x00, 0xe0, 0xbb},
+ {0x08, 0x00, 0x0b, 0xbb},
+ {0x21, 0x00, 0x0c, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x02, 0xcc},
+ {0xb6, 0x02, 0x80, 0xcc},
+ {0xb6, 0x05, 0x01, 0xcc},
+ {0xb6, 0x04, 0xe0, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x05, 0xcc},
+ {0xb6, 0x18, 0x02, 0xcc},
+ {0xb6, 0x17, 0x58, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+#endif
+static const u8 mi1320_soc_InitQVGA[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd1, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x07, 0x00, 0xe0, 0xbb},
+ {0x08, 0x00, 0x0b, 0xbb},
+ {0x21, 0x00, 0x0c, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 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, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+#if 0 /* JPEG vc0323 */
+static const u8 mi1320_soc_InitQVGA_JPG[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x23, 0xe0, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x02, 0xcc},
+ {0xb3, 0x17, 0x7f, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb8, 0x00, 0x00, 0xcc},
+ {0xbc, 0x00, 0xd1, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0xc8, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x10, 0xdd},
+ {0x07, 0x00, 0xe0, 0xbb},
+ {0x08, 0x00, 0x0b, 0xbb},
+ {0x21, 0x00, 0x0c, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {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, 0x05, 0xcc},
+ {0xb6, 0x18, 0x00, 0xcc},
+ {0xb6, 0x17, 0x96, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {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, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {}
+};
+#endif
+#if 0 /* JPEG vc0323 */
+static const u8 mi1320_soc_InitSXGA_JPG[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0xb0, 0x04, 0x02, 0xcc},
+ {0x00, 0x00, 0x33, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x00, 0xcc},
+ {0xb3, 0x06, 0x00, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x04, 0xcc},
+ {0xb3, 0x23, 0x00, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x5b, 0x00, 0x01, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xb6, 0x00, 0x00, 0xcc},
+ {0xb6, 0x03, 0x05, 0xcc},
+ {0xb6, 0x02, 0x00, 0xcc},
+ {0xb6, 0x05, 0x04, 0xcc},
+ {0xb6, 0x04, 0x00, 0xcc},
+ {0xb6, 0x12, 0xf8, 0xcc},
+ {0xb6, 0x13, 0x29, 0xcc},
+ {0xb6, 0x18, 0x0a, 0xcc},
+ {0xb6, 0x17, 0x00, 0xcc},
+ {0xb6, 0x16, 0x00, 0xcc},
+ {0xb6, 0x22, 0x12, 0xcc},
+ {0xb6, 0x23, 0x0b, 0xcc},
+ {0xbf, 0xc0, 0x39, 0xcc},
+ {0xbf, 0xc1, 0x04, 0xcc},
+ {0xbf, 0xcc, 0x00, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x13, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x00, 0x85, 0xbb},
+ {0x08, 0x00, 0x27, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0x0d, 0xbb},
+ {0x3a, 0x06, 0x1b, 0xbb},
+ {0x3b, 0x00, 0x95, 0xbb},
+ {0x3c, 0x04, 0xdb, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x58, 0x02, 0x66, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0x5a, 0x01, 0x33, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x64, 0x5e, 0x1c, 0xbb},
+ {0x2f, 0x90, 0x00, 0xbb},
+ {}
+};
+#endif
+static const u8 mi1320_soc_InitSXGA[][4] = {
+ {0xb3, 0x01, 0x01, 0xcc},
+ {0xb0, 0x03, 0x19, 0xcc},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xb3, 0x00, 0x64, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xb3, 0x05, 0x01, 0xcc},
+ {0xb3, 0x06, 0x01, 0xcc},
+ {0xb3, 0x08, 0x01, 0xcc},
+ {0xb3, 0x09, 0x0c, 0xcc},
+ {0xb3, 0x34, 0x02, 0xcc},
+ {0xb3, 0x35, 0xc8, 0xcc},
+ {0xb3, 0x02, 0x00, 0xcc},
+ {0xb3, 0x03, 0x0a, 0xcc},
+ {0xb3, 0x04, 0x05, 0xcc},
+ {0xb3, 0x20, 0x00, 0xcc},
+ {0xb3, 0x21, 0x00, 0xcc},
+ {0xb3, 0x22, 0x04, 0xcc},
+ {0xb3, 0x23, 0x00, 0xcc},
+ {0xb3, 0x14, 0x00, 0xcc},
+ {0xb3, 0x15, 0x00, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x17, 0xff, 0xcc},
+ {0xb3, 0x00, 0x67, 0xcc},
+ {0xbc, 0x00, 0x71, 0xcc},
+ {0xbc, 0x01, 0x01, 0xcc},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0xc8, 0x9f, 0x0b, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0x5b, 0x00, 0x01, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x00, 0x00, 0x30, 0xdd},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x00, 0x00, 0x20, 0xdd},
+ {0xbf, 0xc0, 0x26, 0xcc},
+ {0xbf, 0xc1, 0x02, 0xcc},
+ {0xbf, 0xcc, 0x04, 0xcc},
+ {0xb3, 0x01, 0x41, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x78, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x01, 0x42, 0xbb},
+ {0x08, 0x00, 0x11, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0xca, 0xbb},
+ {0x3a, 0x06, 0x80, 0xbb},
+ {0x3b, 0x01, 0x52, 0xbb},
+ {0x3c, 0x05, 0x40, 0xbb},
+ {0x57, 0x01, 0x9c, 0xbb},
+ {0x58, 0x01, 0xee, 0xbb},
+ {0x59, 0x00, 0xf0, 0xbb},
+ {0x5a, 0x01, 0x20, 0xbb},
+ {0x5c, 0x1d, 0x17, 0xbb},
+ {0x5d, 0x22, 0x1c, 0xbb},
+ {0x64, 0x1e, 0x1c, 0xbb},
+ {0x5b, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x22, 0xa0, 0x78, 0xbb},
+ {0x23, 0xa0, 0x78, 0xbb},
+ {0x24, 0x7f, 0x00, 0xbb},
+ {0x28, 0xea, 0x02, 0xbb},
+ {0x29, 0x86, 0x7a, 0xbb},
+ {0x5e, 0x52, 0x4c, 0xbb},
+ {0x5f, 0x20, 0x24, 0xbb},
+ {0x60, 0x00, 0x02, 0xbb},
+ {0x02, 0x00, 0xee, 0xbb},
+ {0x03, 0x39, 0x23, 0xbb},
+ {0x04, 0x07, 0x24, 0xbb},
+ {0x09, 0x00, 0xc0, 0xbb},
+ {0x0a, 0x00, 0x79, 0xbb},
+ {0x0b, 0x00, 0x04, 0xbb},
+ {0x0c, 0x00, 0x5c, 0xbb},
+ {0x0d, 0x00, 0xd9, 0xbb},
+ {0x0e, 0x00, 0x53, 0xbb},
+ {0x0f, 0x00, 0x21, 0xbb},
+ {0x10, 0x00, 0xa4, 0xbb},
+ {0x11, 0x00, 0xe5, 0xbb},
+ {0x15, 0x00, 0x00, 0xbb},
+ {0x16, 0x00, 0x00, 0xbb},
+ {0x17, 0x00, 0x00, 0xbb},
+ {0x18, 0x00, 0x00, 0xbb},
+ {0x19, 0x00, 0x00, 0xbb},
+ {0x1a, 0x00, 0x00, 0xbb},
+ {0x1b, 0x00, 0x00, 0xbb},
+ {0x1c, 0x00, 0x00, 0xbb},
+ {0x1d, 0x00, 0x00, 0xbb},
+ {0x1e, 0x00, 0x00, 0xbb},
+ {0xf0, 0x00, 0x01, 0xbb},
+ {0x06, 0xe0, 0x0e, 0xbb},
+ {0x06, 0x60, 0x0e, 0xbb},
+ {0xb3, 0x5c, 0x01, 0xcc},
+ {0xf0, 0x00, 0x00, 0xbb},
+ {0x05, 0x01, 0x13, 0xbb},
+ {0x06, 0x00, 0x11, 0xbb},
+ {0x07, 0x00, 0x85, 0xbb},
+ {0x08, 0x00, 0x27, 0xbb},
+ {0x20, 0x01, 0x03, 0xbb},
+ {0x21, 0x80, 0x00, 0xbb},
+ {0x22, 0x0d, 0x0f, 0xbb},
+ {0x24, 0x80, 0x00, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0xf0, 0x00, 0x02, 0xbb},
+ {0x39, 0x03, 0x0d, 0xbb},
+ {0x3a, 0x06, 0x1b, 0xbb},
+ {0x3b, 0x00, 0x95, 0xbb},
+ {0x3c, 0x04, 0xdb, 0xbb},
+ {0x57, 0x02, 0x00, 0xbb},
+ {0x58, 0x02, 0x66, 0xbb},
+ {0x59, 0x00, 0xff, 0xbb},
+ {0x5a, 0x01, 0x33, 0xbb},
+ {0x5c, 0x12, 0x0d, 0xbb},
+ {0x5d, 0x16, 0x11, 0xbb},
+ {0x64, 0x5e, 0x1c, 0xbb},
+ {}
+};
static const __u8 po3130_gamma[17] = {
0x00, 0x13, 0x38, 0x59, 0x79, 0x92, 0xa7, 0xb9, 0xc8,
0xd4, 0xdf, 0xe7, 0xee, 0xf4, 0xf9, 0xfc, 0xff
@@ -1903,26 +2665,55 @@ static const __u8 po1200_initVGA_data[][4] = {
};
struct sensor_info {
- int sensorId;
- __u8 I2cAdd;
- __u8 IdAdd;
- __u16 VpId;
- __u8 m1;
- __u8 m2;
- __u8 op;
- };
+ s8 sensorId;
+ u8 I2cAdd;
+ u8 IdAdd;
+ u16 VpId;
+ u8 m1;
+ u8 m2;
+ u8 op;
+};
static const struct sensor_info sensor_info_data[] = {
/* sensorId, I2cAdd, IdAdd, VpId, m1, m2, op */
+#if 1
+ {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05},
+ {-1, 0x80 | 0x20, 0x82, 0x0000, 0x24, 0x25, 0x01},
+/* (tested in vc032x_probe_sensor) */
+/* {-1, 0x80 | 0x20, 0x83, 0x0000, 0x24, 0x25, 0x01}, */
+ {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
+ {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_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
+ {-1, 0x80 | 0x21, 0x0a, 0x0000, 0x21, 0x20, 0x05},
+ {-1, 0x80 | 0x40, 0x00, 0x0000, 0x20, 0x22, 0x05},
+ {SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
+/* {SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x0000, 0x24, 0x25, 0x01}, */
+ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+/* {SENSOR_MI1310_SOC, 0x80 | 0x5d, 0x00, 0x0000, 0x24, 0x25, 0x01}, */
+/* {-1, 0x80 | 0x30, 0x0a, 0x0000, 0x25, 0x24, 0x05}, */
+ {-1, 0x80 | 0x11, 0x39, 0x0000, 0x24, 0x25, 0x01},
+ {SENSOR_PO1200, 0x80 | 0x5c, 0x00, 0x1200, 0x67, 0x67, 0x01},
+ {-1, 0x80 | 0x2d, 0x00, 0x0000, 0x65, 0x67, 0x01},
+ {-1, 0x80 | 0x6e, 0x00, 0x0000, 0x24, 0x25, 0x01},
+ {-1, 0x80 | 0x56, 0x01, 0x0000, 0x64, 0x67, 0x01},
+ {SENSOR_MI1320_SOC, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x67, 0x01},
+/*fixme: previously detected?*/
+ {SENSOR_MI1320, 0x80 | 0x48, 0x00, 0x148c, 0x64, 0x65, 0x01},
+/*fixme: not in the ms-win probe - may be found before?*/
+ {SENSOR_OV7670, 0x80 | 0x21, 0x0a, 0x7673, 0x66, 0x67, 0x05},
+#else
{SENSOR_HV7131R, 0x80 | 0x11, 0x00, 0x0209, 0x24, 0x25, 0x01},
{SENSOR_OV7660, 0x80 | 0x21, 0x0a, 0x7660, 0x26, 0x26, 0x05},
{SENSOR_PO3130NC, 0x80 | 0x76, 0x00, 0x3130, 0x24, 0x25, 0x01},
- {SENSOR_MI1320, 0x80 | 0xc8, 0x00, 0x148c, 0x64, 0x65, 0x01},
+ {SENSOR_MI1320, 0x80 | 0x48, 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},
+#endif
};
/* read 'len' bytes in gspca_dev->usb_buf */
@@ -1957,7 +2748,7 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
u16 address)
{
struct usb_device *dev = gspca_dev->dev;
- __u8 ldata, mdata, hdata;
+ u8 ldata, mdata, hdata;
int retry = 50;
reg_r(gspca_dev, 0xa1, 0xb33f, 1);
@@ -1970,9 +2761,11 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
reg_w(dev, 0xa0, 0x02, 0xb339);
do {
- msleep(8);
reg_r(gspca_dev, 0xa1, 0xb33b, 1);
- } while (retry-- && gspca_dev->usb_buf[0]);
+ if (gspca_dev->usb_buf[0] == 0x00)
+ break;
+ msleep(40);
+ } while (--retry >= 0);
reg_r(gspca_dev, 0xa1, 0xb33e, 1);
ldata = gspca_dev->usb_buf[0];
@@ -1993,7 +2786,7 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
{
struct usb_device *dev = gspca_dev->dev;
int i;
- __u16 value;
+ u16 value;
const struct sensor_info *ptsensor_info;
reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
@@ -2008,45 +2801,40 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd);
- 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;
+ if (value == 0 && ptsensor_info->IdAdd == 0x82)
+ value = read_sensor_register(gspca_dev, 0x83);
+ if (value != 0) {
+ PDEBUG(D_ERR|D_PROBE, "Sensor ID %04x (%d)",
+ value, i);
+ if (value == ptsensor_info->VpId)
+ return ptsensor_info->sensorId;
+
+ switch (value) {
+ case 0x7673:
+ return SENSOR_OV7670;
+ case 0x8243:
+ return SENSOR_MI0360;
+ }
+/*fixme: should return here*/
+ }
}
return -1;
}
static void i2c_write(struct gspca_dev *gspca_dev,
- __u8 reg, const __u8 *val, __u8 size)
+ u8 reg, const u8 *val,
+ u8 size) /* 1 or 2 */
{
struct usb_device *dev = gspca_dev->dev;
int retry;
-#ifdef GSPCA_DEBUG
- if (size > 3 || size < 1)
- return;
-#endif
reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+/*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/
reg_w(dev, 0xa0, size, 0xb334);
reg_w(dev, 0xa0, reg, 0xb33a);
- switch (size) {
- case 1:
- reg_w(dev, 0xa0, val[0], 0xb336);
- break;
- case 2:
- reg_w(dev, 0xa0, val[0], 0xb336);
+ reg_w(dev, 0xa0, val[0], 0xb336);
+ if (size > 1)
reg_w(dev, 0xa0, val[1], 0xb337);
- break;
- default:
-/* case 3: */
- reg_w(dev, 0xa0, val[0], 0xb336);
- reg_w(dev, 0xa0, val[1], 0xb337);
- reg_w(dev, 0xa0, val[2], 0xb338);
- break;
- }
reg_w(dev, 0xa0, 0x01, 0xb339);
retry = 4;
do {
@@ -2117,6 +2905,17 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct usb_device *dev = gspca_dev->dev;
struct cam *cam;
int sensor;
+ static u8 npkt[] = { /* number of packets per ISOC message */
+ 64, /* HV7131R 0 */
+ 32, /* MI0360 1 */
+ 32, /* MI1310_SOC 2 */
+ 64, /* MI1320 3 */
+ 128, /* MI1320_SOC 4 */
+ 32, /* OV7660 5 */
+ 64, /* OV7670 6 */
+ 128, /* PO1200 7 */
+ 128, /* PO3130NC 8 */
+ };
cam = &gspca_dev->cam;
sd->bridge = id->driver_info;
@@ -2141,6 +2940,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
case SENSOR_MI1320:
PDEBUG(D_PROBE, "Find Sensor MI1320");
break;
+ case SENSOR_MI1320_SOC:
+ PDEBUG(D_PROBE, "Find Sensor MI1320_SOC");
+ break;
case SENSOR_OV7660:
PDEBUG(D_PROBE, "Find Sensor OV7660");
break;
@@ -2160,17 +2962,28 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = vc0321_mode;
cam->nmodes = ARRAY_SIZE(vc0321_mode);
} else {
- if (sensor != SENSOR_PO1200) {
- cam->cam_mode = vc0323_mode;
- if (sd->sensor != SENSOR_MI1310_SOC)
- cam->nmodes = ARRAY_SIZE(vc0323_mode);
- else /* no SXGA */
- cam->nmodes = ARRAY_SIZE(vc0323_mode) - 1;
- } else {
+ switch (sensor) {
+ case SENSOR_PO1200:
cam->cam_mode = svga_mode;
cam->nmodes = ARRAY_SIZE(svga_mode);
+ break;
+ case SENSOR_MI1310_SOC:
+ cam->cam_mode = vc0323_mode;
+ cam->nmodes = ARRAY_SIZE(vc0323_mode);
+ break;
+ case SENSOR_MI1320_SOC:
+ cam->cam_mode = bi_mode;
+ cam->nmodes = ARRAY_SIZE(bi_mode);
+ cam->input_flags = V4L2_IN_ST_VFLIP |
+ V4L2_IN_ST_HFLIP;
+ break;
+ default:
+ cam->cam_mode = vc0323_mode;
+ cam->nmodes = ARRAY_SIZE(vc0323_mode) - 1;
+ break;
}
}
+ cam->npkt = npkt[sd->sensor];
sd->hflip = HFLIP_DEF;
sd->vflip = VFLIP_DEF;
@@ -2271,6 +3084,16 @@ static int sd_start(struct gspca_dev *gspca_dev)
const __u8 *GammaT = NULL;
const __u8 *MatrixT = NULL;
int mode;
+ static const u8 (*mi1320_soc_init[])[4] = {
+ mi1320_soc_InitSXGA,
+ mi1320_soc_InitVGA,
+ mi1320_soc_InitQVGA,
+#if 0 /* JPEG vc0323 */
+ mi1320_soc_InitSXGA_JPG,
+ mi1320_soc_InitVGA_JPG,
+ mi1320_soc_InitQVGA_JPG
+#endif
+ };
/* Assume start use the good resolution from gspca_dev->mode */
if (sd->bridge == BRIDGE_VC0321) {
@@ -2278,6 +3101,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+ sd->image_offset = 46;
+ } else {
+ if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat
+ == V4L2_PIX_FMT_JPEG)
+ sd->image_offset = 0;
+ else
+ sd->image_offset = 32;
}
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
@@ -2325,7 +3155,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
init = mi1310_socinitVGA_JPG; /* 640x480 */
break;
default:
- init = mi1310_soc_InitSXGA_JPG; /* 1280xq024 */
+ init = mi1310_soc_InitSXGA_JPG; /* 1280x1024 */
break;
}
break;
@@ -2337,6 +3167,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
else
init = mi1320_initVGA_data; /* 640x480 */
break;
+ case SENSOR_MI1320_SOC:
+ GammaT = mi1320_gamma;
+ MatrixT = mi1320_matrix;
+ init = mi1320_soc_init[mode];
+ break;
case SENSOR_PO3130NC:
GammaT = po3130_gamma;
MatrixT = po3130_matrix;
@@ -2407,12 +3242,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
"vc032x header packet found len %d", len);
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
data, 0);
- if (sd->bridge == BRIDGE_VC0321) {
-#define VCHDRSZ 46
- data += VCHDRSZ;
- len -= VCHDRSZ;
-#undef VCHDRSZ
- }
+ data += sd->image_offset;
+ len -= sd->image_offset;
gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
data, len);
return;
@@ -2545,6 +3376,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{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, 0x6001), .driver_info = BRIDGE_VC0323},
{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.c b/linux/drivers/media/video/gspca/zc3xx.c
index ad385b9a0..2855ebf90 100644
--- a/linux/drivers/media/video/gspca/zc3xx.c
+++ b/linux/drivers/media/video/gspca/zc3xx.c
@@ -23,6 +23,7 @@
#define MODULE_NAME "zc3xx"
#include "gspca.h"
+#include "jpeg.h"
MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>, "
"Serge A. Suchkov <Serge.A.S@tochka.ru>");
@@ -32,7 +33,6 @@ MODULE_LICENSE("GPL");
static int force_sensor = -1;
#define QUANT_VAL 1 /* quantization table */
-#include "jpeg.h"
#include "zc3xx-reg.h"
/* specific webcam descriptor */
@@ -45,6 +45,10 @@ struct sd {
__u8 autogain;
__u8 lightfreq;
__u8 sharpness;
+ u8 quality; /* image quality */
+#define QUALITY_MIN 40
+#define QUALITY_MAX 60
+#define QUALITY_DEF 50
signed char sensor; /* Type of image sensor chip */
/* !! values used in different tables */
@@ -69,6 +73,8 @@ struct sd {
#define SENSOR_TAS5130C_VF0250 17
#define SENSOR_MAX 18
unsigned short chip_revision;
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -6330,7 +6336,7 @@ static __u16 i2c_read(struct gspca_dev *gspca_dev,
retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */
retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */
retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */
- PDEBUG(D_USBO, "i2c r [%02x] -> %04x (%02x)",
+ PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)",
reg, retval, retbyte);
return retval;
}
@@ -6891,7 +6897,6 @@ static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
{0x8001, 0x13},
{0x8000, 0x14}, /* CS2102K */
{0x8400, 0x15}, /* TAS5130K */
- {0x4001, 0x16}, /* ADCM2700 */
};
static int vga_3wr_probe(struct gspca_dev *gspca_dev)
@@ -6927,12 +6932,15 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
retword |= reg_r(gspca_dev, 0x000a);
PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", retword);
reg_r(gspca_dev, 0x0010);
- /* this is tested only once anyway */
- for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) {
- if (chipset_revision_sensor[i].revision == retword) {
- sd->chip_revision = retword;
- send_unknown(dev, SENSOR_PB0330);
- return chipset_revision_sensor[i].internal_sensor_id;
+ /* value 0x4001 is meaningless */
+ if (retword != 0x4001) {
+ for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) {
+ if (chipset_revision_sensor[i].revision == retword) {
+ sd->chip_revision = retword;
+ send_unknown(dev, SENSOR_PB0330);
+ return chipset_revision_sensor[i]
+ .internal_sensor_id;
+ }
}
}
@@ -7003,12 +7011,12 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
reg_w(dev, 0x01, 0x0001);
reg_w(dev, 0x03, 0x0012);
reg_w(dev, 0x01, 0x0012);
- reg_w(dev, 0x05, 0x0001);
+ reg_w(dev, 0x05, 0x0012);
reg_w(dev, 0xd3, 0x008b);
retword = i2c_read(gspca_dev, 0x01);
if (retword != 0) {
PDEBUG(D_PROBE, "probe 3wr vga type 0a ? ret: %04x", retword);
- return retword;
+ return 0x16; /* adcm2700 (6100/6200) */
}
return -1;
}
@@ -7206,6 +7214,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->gamma = gamma[(int) sd->sensor];
sd->autogain = sd_ctrls[SD_AUTOGAIN].qctrl.default_value;
sd->lightfreq = sd_ctrls[SD_FREQ].qctrl.default_value;
+ sd->quality = QUALITY_DEF;
switch (sd->sensor) {
case SENSOR_GC0305:
@@ -7261,6 +7270,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* 17 */
};
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x21); /* JPEG 422 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
zc3_init = init_tb[(int) sd->sensor][mode];
switch (sd->sensor) {
@@ -7398,6 +7413,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ kfree(sd->jpeg_hdr);
if (!gspca_dev->present)
return;
send_unknown(gspca_dev->dev, sd->sensor);
@@ -7408,12 +7424,15 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
__u8 *data,
int len)
{
+ struct sd *sd = (struct sd *) gspca_dev;
if (data[0] == 0xff && data[1] == 0xd8) { /* start of frame */
frame = gspca_frame_add(gspca_dev, LAST_PACKET, frame,
data, 0);
/* put the JPEG header in the new frame */
- jpeg_put_header(gspca_dev, frame, 0x21);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
+
/* remove the webcam's header:
* ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp
* - 'ss ss' is the frame sequence number (BE)
@@ -7555,6 +7574,34 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
@@ -7565,6 +7612,8 @@ static const struct sd_desc sd_desc = {
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
static const __devinitdata struct usb_device_id device_table[] = {
@@ -7615,7 +7664,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x055f, 0xd004)},
{USB_DEVICE(0x0698, 0x2003)},
{USB_DEVICE(0x0ac8, 0x0301), .driver_info = SENSOR_PAS106},
- {USB_DEVICE(0x0ac8, 0x0302)},
+ {USB_DEVICE(0x0ac8, 0x0302), .driver_info = SENSOR_PAS106},
{USB_DEVICE(0x0ac8, 0x301b)},
{USB_DEVICE(0x0ac8, 0x303b)},
{USB_DEVICE(0x0ac8, 0x305b), .driver_info = SENSOR_TAS5130C_VF0250},