summaryrefslogtreecommitdiffstats
path: root/drivers/media/video/gspca
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/gspca')
-rw-r--r--drivers/media/video/gspca/Kconfig10
-rw-r--r--drivers/media/video/gspca/Makefile2
-rw-r--r--drivers/media/video/gspca/benq.c7
-rw-r--r--drivers/media/video/gspca/gl860/Makefile2
-rw-r--r--drivers/media/video/gspca/gl860/gl860.c1
-rw-r--r--drivers/media/video/gspca/gspca.c73
-rw-r--r--drivers/media/video/gspca/gspca.h5
-rw-r--r--drivers/media/video/gspca/jl2005bcd.c554
-rw-r--r--drivers/media/video/gspca/konica.c3
-rw-r--r--drivers/media/video/gspca/m5602/Makefile2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c4
-rw-r--r--drivers/media/video/gspca/m5602/m5602_mt9m111.h2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov7660.h2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.h2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_po1030.h2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.h2
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.h2
-rw-r--r--drivers/media/video/gspca/mars.c1
-rw-r--r--drivers/media/video/gspca/nw80x.c2
-rw-r--r--drivers/media/video/gspca/ov519.c5
-rw-r--r--drivers/media/video/gspca/ov534_9.c184
-rw-r--r--drivers/media/video/gspca/pac207.c10
-rw-r--r--drivers/media/video/gspca/pac7302.c584
-rw-r--r--drivers/media/video/gspca/se401.c10
-rw-r--r--drivers/media/video/gspca/sn9c20x.c1176
-rw-r--r--drivers/media/video/gspca/sonixb.c15
-rw-r--r--drivers/media/video/gspca/sonixj.c203
-rw-r--r--drivers/media/video/gspca/spca561.c2
-rw-r--r--drivers/media/video/gspca/stv06xx/Makefile2
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c8
-rw-r--r--drivers/media/video/gspca/t613.c25
-rw-r--r--drivers/media/video/gspca/topro.c2
-rw-r--r--drivers/media/video/gspca/vicam.c3
-rw-r--r--drivers/media/video/gspca/xirlink_cit.c6
-rw-r--r--drivers/media/video/gspca/zc3xx.c443
35 files changed, 2017 insertions, 1339 deletions
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index 103af3fe5aa..dfe268bfa4f 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -77,6 +77,16 @@ config USB_GSPCA_JEILINJ
To compile this driver as a module, choose M here: the
module will be called gspca_jeilinj.
+config USB_GSPCA_JL2005BCD
+ tristate "JL2005B/C/D USB V4L2 driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based the
+ JL2005B, JL2005C, or JL2005D chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_jl2005bcd.
+
config USB_GSPCA_KINECT
tristate "Kinect sensor device USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index f345f494d0f..79ebe46e1ad 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o
obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o
+obj-$(CONFIG_USB_GSPCA_JL2005BCD) += gspca_jl2005bcd.o
obj-$(CONFIG_USB_GSPCA_KINECT) += gspca_kinect.o
obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o
obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o
@@ -49,6 +50,7 @@ gspca_cpia1-objs := cpia1.o
gspca_etoms-objs := etoms.o
gspca_finepix-objs := finepix.o
gspca_jeilinj-objs := jeilinj.o
+gspca_jl2005bcd-objs := jl2005bcd.o
gspca_kinect-objs := kinect.o
gspca_konica-objs := konica.o
gspca_mars-objs := mars.o
diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c
index 636627b57dc..9769f17915c 100644
--- a/drivers/media/video/gspca/benq.c
+++ b/drivers/media/video/gspca/benq.c
@@ -76,7 +76,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
gspca_dev->cam.cam_mode = vga_mode;
gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
gspca_dev->cam.no_urb_create = 1;
- gspca_dev->cam.reverse_alts = 1;
return 0;
}
@@ -135,13 +134,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
static void sd_stopN(struct gspca_dev *gspca_dev)
{
+ struct usb_interface *intf;
+
reg_w(gspca_dev, 0x003c, 0x0003);
reg_w(gspca_dev, 0x003c, 0x0004);
reg_w(gspca_dev, 0x003c, 0x0005);
reg_w(gspca_dev, 0x003c, 0x0006);
reg_w(gspca_dev, 0x003c, 0x0007);
+
+ intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
usb_set_interface(gspca_dev->dev, gspca_dev->iface,
- gspca_dev->nbalt - 1);
+ intf->num_altsetting - 1);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
diff --git a/drivers/media/video/gspca/gl860/Makefile b/drivers/media/video/gspca/gl860/Makefile
index f511eccdfd9..773ea342656 100644
--- a/drivers/media/video/gspca/gl860/Makefile
+++ b/drivers/media/video/gspca/gl860/Makefile
@@ -6,5 +6,5 @@ gspca_gl860-objs := gl860.o \
gl860-ov9655.o \
gl860-mi2020.o
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index a8f54c20e58..c84e26006fc 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -337,7 +337,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
return -1;
cam = &gspca_dev->cam;
- gspca_dev->nbalt = 4;
switch (sd->sensor) {
case ID_MI1320:
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 2ca10dfec91..ca5a2b139d0 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -633,23 +633,32 @@ static u32 which_bandwidth(struct gspca_dev *gspca_dev)
u32 bandwidth;
int i;
+ /* get the (max) image size */
i = gspca_dev->curr_mode;
bandwidth = gspca_dev->cam.cam_mode[i].sizeimage;
- /* if the image is compressed, estimate the mean image size */
- if (bandwidth < gspca_dev->cam.cam_mode[i].width *
+ /* if the image is compressed, estimate its mean size */
+ if (!gspca_dev->cam.needs_full_bandwidth &&
+ bandwidth < gspca_dev->cam.cam_mode[i].width *
gspca_dev->cam.cam_mode[i].height)
- bandwidth /= 3;
+ bandwidth = bandwidth * 3 / 8; /* 0.375 */
/* estimate the frame rate */
if (gspca_dev->sd_desc->get_streamparm) {
struct v4l2_streamparm parm;
- parm.parm.capture.timeperframe.denominator = 15;
gspca_dev->sd_desc->get_streamparm(gspca_dev, &parm);
bandwidth *= parm.parm.capture.timeperframe.denominator;
+ bandwidth /= parm.parm.capture.timeperframe.numerator;
} else {
- bandwidth *= 15; /* 15 fps */
+
+ /* don't hope more than 15 fps with USB 1.1 and
+ * image resolution >= 640x480 */
+ if (gspca_dev->width >= 640
+ && gspca_dev->dev->speed == USB_SPEED_FULL)
+ bandwidth *= 15; /* 15 fps */
+ else
+ bandwidth *= 30; /* 30 fps */
}
PDEBUG(D_STREAM, "min bandwidth: %d", bandwidth);
@@ -667,9 +676,8 @@ struct ep_tb_s {
* build the table of the endpoints
* and compute the minimum bandwidth for the image transfer
*/
-static int build_ep_tb(struct gspca_dev *gspca_dev,
+static int build_isoc_ep_tb(struct gspca_dev *gspca_dev,
struct usb_interface *intf,
- int xfer,
struct ep_tb_s *ep_tb)
{
struct usb_host_endpoint *ep;
@@ -687,17 +695,21 @@ static int build_ep_tb(struct gspca_dev *gspca_dev,
ep_tb->bandwidth = 2000 * 2000 * 120;
found = 0;
for (j = 0; j < nbalt; j++) {
- ep = alt_xfer(&intf->altsetting[j], xfer);
+ ep = alt_xfer(&intf->altsetting[j],
+ USB_ENDPOINT_XFER_ISOC);
if (ep == NULL)
continue;
+ if (ep->desc.bInterval == 0) {
+ pr_err("alt %d iso endp with 0 interval\n", j);
+ continue;
+ }
psize = le16_to_cpu(ep->desc.wMaxPacketSize);
- if (!gspca_dev->cam.bulk) /* isoc */
- psize = (psize & 0x07ff) *
- (1 + ((psize >> 11) & 3));
- bandwidth = psize * ep->desc.bInterval * 1000;
+ psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
+ bandwidth = psize * 1000;
if (gspca_dev->dev->speed == USB_SPEED_HIGH
|| gspca_dev->dev->speed == USB_SPEED_SUPER)
bandwidth *= 8;
+ bandwidth /= 1 << (ep->desc.bInterval - 1);
if (bandwidth <= last_bw)
continue;
if (bandwidth < ep_tb->bandwidth) {
@@ -715,6 +727,23 @@ static int build_ep_tb(struct gspca_dev *gspca_dev,
ep_tb++;
}
+ /*
+ * If the camera:
+ * has a usb audio class interface (a built in usb mic); and
+ * is a usb 1 full speed device; and
+ * uses the max full speed iso bandwidth; and
+ * and has more than 1 alt setting
+ * then skip the highest alt setting to spare bandwidth for the mic
+ */
+ if (gspca_dev->audio &&
+ gspca_dev->dev->speed == USB_SPEED_FULL &&
+ last_bw >= 1000000 &&
+ i > 1) {
+ PDEBUG(D_STREAM, "dev has usb audio, skipping highest alt");
+ i--;
+ ep_tb--;
+ }
+
/* get the requested bandwidth and start at the highest atlsetting */
bandwidth = which_bandwidth(gspca_dev);
ep_tb--;
@@ -790,10 +819,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
ep->desc.bEndpointAddress);
urb->transfer_flags = URB_ISO_ASAP
| URB_NO_TRANSFER_DMA_MAP;
- if (gspca_dev->dev->speed == USB_SPEED_LOW)
- urb->interval = ep->desc.bInterval;
- else
- urb->interval = 1 << (ep->desc.bInterval - 1);
+ urb->interval = 1 << (ep->desc.bInterval - 1);
urb->complete = isoc_irq;
urb->number_of_packets = npkt;
for (i = 0; i < npkt; i++) {
@@ -848,7 +874,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
xfer = gspca_dev->cam.bulk ? USB_ENDPOINT_XFER_BULK
: USB_ENDPOINT_XFER_ISOC;
- /* if the subdriver forced an altsetting, get the endpoint */
+ /* if bulk or the subdriver forced an altsetting, get the endpoint */
if (gspca_dev->alt != 0) {
gspca_dev->alt--; /* (previous version compatibility) */
ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer);
@@ -863,7 +889,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
/* else, compute the minimum bandwidth
* and build the endpoint table */
- alt_idx = build_ep_tb(gspca_dev, intf, xfer, ep_tb);
+ alt_idx = build_isoc_ep_tb(gspca_dev, intf, ep_tb);
if (alt_idx <= 0) {
pr_err("no transfer endpoint found\n");
ret = -EIO;
@@ -880,7 +906,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
for (;;) {
if (alt != gspca_dev->alt) {
alt = gspca_dev->alt;
- if (gspca_dev->nbalt > 1) {
+ if (intf->num_altsetting > 1) {
ret = usb_set_interface(gspca_dev->dev,
gspca_dev->iface,
alt);
@@ -2300,15 +2326,14 @@ int gspca_dev_probe2(struct usb_interface *intf,
}
gspca_dev->dev = dev;
gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber;
- gspca_dev->nbalt = intf->num_altsetting;
/* check if any audio device */
- if (dev->config->desc.bNumInterfaces != 1) {
+ if (dev->actconfig->desc.bNumInterfaces != 1) {
int i;
struct usb_interface *intf2;
- for (i = 0; i < dev->config->desc.bNumInterfaces; i++) {
- intf2 = dev->config->interface[i];
+ for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
+ intf2 = dev->actconfig->interface[i];
if (intf2 != NULL
&& intf2->altsetting != NULL
&& intf2->altsetting->desc.bInterfaceClass ==
@@ -2389,7 +2414,7 @@ int gspca_dev_probe(struct usb_interface *intf,
}
/* the USB video interface must be the first one */
- if (dev->config->desc.bNumInterfaces != 1
+ if (dev->actconfig->desc.bNumInterfaces != 1
&& intf->cur_altsetting->desc.bInterfaceNumber != 0)
return -ENODEV;
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index e444f16e149..589009f4496 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -69,7 +69,9 @@ struct cam {
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 */
- u8 reverse_alts; /* Alt settings are in high to low order */
+ u8 needs_full_bandwidth;/* Set this flag to notify the bandwidth calc.
+ * code that the cam fills all image buffers to
+ * the max, even when using compression. */
};
struct gspca_dev;
@@ -208,7 +210,6 @@ struct gspca_dev {
char memory; /* memory type (V4L2_MEMORY_xxx) */
__u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */
- __u8 nbalt; /* number of USB alternate settings */
u8 audio; /* presence of audio device */
};
diff --git a/drivers/media/video/gspca/jl2005bcd.c b/drivers/media/video/gspca/jl2005bcd.c
new file mode 100644
index 00000000000..53f58ef367c
--- /dev/null
+++ b/drivers/media/video/gspca/jl2005bcd.c
@@ -0,0 +1,554 @@
+/*
+ * Jeilin JL2005B/C/D library
+ *
+ * Copyright (C) 2011 Theodore Kilgore <kilgota@auburn.edu>
+ *
+ * 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
+ */
+
+#define MODULE_NAME "jl2005bcd"
+
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include "gspca.h"
+
+
+MODULE_AUTHOR("Theodore Kilgore <kilgota@auburn.edu>");
+MODULE_DESCRIPTION("JL2005B/C/D USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Default timeouts, in ms */
+#define JL2005C_CMD_TIMEOUT 500
+#define JL2005C_DATA_TIMEOUT 1000
+
+/* Maximum transfer size to use. */
+#define JL2005C_MAX_TRANSFER 0x200
+#define FRAME_HEADER_LEN 16
+
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ unsigned char firmware_id[6];
+ const struct v4l2_pix_format *cap_mode;
+ /* Driver stuff */
+ struct work_struct work_struct;
+ struct workqueue_struct *work_thread;
+ u8 frame_brightness;
+ int block_size; /* block size of camera */
+ int vga; /* 1 if vga cam, 0 if cif cam */
+};
+
+
+/* Camera has two resolution settings. What they are depends on model. */
+static const struct v4l2_pix_format cif_mode[] = {
+ {176, 144, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ {352, 288, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ {640, 480, V4L2_PIX_FMT_JL2005BCD, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+};
+
+/*
+ * cam uses endpoint 0x03 to send commands, 0x84 for read commands,
+ * and 0x82 for bulk data transfer.
+ */
+
+/* All commands are two bytes only */
+static int jl2005c_write2(struct gspca_dev *gspca_dev, unsigned char *command)
+{
+ int retval;
+
+ memcpy(gspca_dev->usb_buf, command, 2);
+ retval = usb_bulk_msg(gspca_dev->dev,
+ usb_sndbulkpipe(gspca_dev->dev, 3),
+ gspca_dev->usb_buf, 2, NULL, 500);
+ if (retval < 0)
+ pr_err("command write [%02x] error %d\n",
+ gspca_dev->usb_buf[0], retval);
+ return retval;
+}
+
+/* Response to a command is one byte in usb_buf[0], only if requested. */
+static int jl2005c_read1(struct gspca_dev *gspca_dev)
+{
+ int retval;
+
+ retval = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x84),
+ gspca_dev->usb_buf, 1, NULL, 500);
+ if (retval < 0)
+ pr_err("read command [0x%02x] error %d\n",
+ gspca_dev->usb_buf[0], retval);
+ return retval;
+}
+
+/* Response appears in gspca_dev->usb_buf[0] */
+static int jl2005c_read_reg(struct gspca_dev *gspca_dev, unsigned char reg)
+{
+ int retval;
+
+ static u8 instruction[2] = {0x95, 0x00};
+ /* put register to read in byte 1 */
+ instruction[1] = reg;
+ /* Send the read request */
+ retval = jl2005c_write2(gspca_dev, instruction);
+ if (retval < 0)
+ return retval;
+ retval = jl2005c_read1(gspca_dev);
+
+ return retval;
+}
+
+static int jl2005c_start_new_frame(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval;
+ int frame_brightness = 0;
+
+ static u8 instruction[2] = {0x7f, 0x01};
+
+ retval = jl2005c_write2(gspca_dev, instruction);
+ if (retval < 0)
+ return retval;
+
+ i = 0;
+ while (i < 20 && !frame_brightness) {
+ /* If we tried 20 times, give up. */
+ retval = jl2005c_read_reg(gspca_dev, 0x7e);
+ if (retval < 0)
+ return retval;
+ frame_brightness = gspca_dev->usb_buf[0];
+ retval = jl2005c_read_reg(gspca_dev, 0x7d);
+ if (retval < 0)
+ return retval;
+ i++;
+ }
+ PDEBUG(D_FRAM, "frame_brightness is 0x%02x", gspca_dev->usb_buf[0]);
+ return retval;
+}
+
+static int jl2005c_write_reg(struct gspca_dev *gspca_dev, unsigned char reg,
+ unsigned char value)
+{
+ int retval;
+ u8 instruction[2];
+
+ instruction[0] = reg;
+ instruction[1] = value;
+
+ retval = jl2005c_write2(gspca_dev, instruction);
+ if (retval < 0)
+ return retval;
+
+ return retval;
+}
+
+static int jl2005c_get_firmware_id(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *)gspca_dev;
+ int i = 0;
+ int retval = -1;
+ unsigned char regs_to_read[] = {0x57, 0x02, 0x03, 0x5d, 0x5e, 0x5f};
+
+ PDEBUG(D_PROBE, "Running jl2005c_get_firmware_id");
+ /* Read the first ID byte once for warmup */
+ retval = jl2005c_read_reg(gspca_dev, regs_to_read[0]);
+ PDEBUG(D_PROBE, "response is %02x", gspca_dev->usb_buf[0]);
+ if (retval < 0)
+ return retval;
+ /* Now actually get the ID string */
+ for (i = 0; i < 6; i++) {
+ retval = jl2005c_read_reg(gspca_dev, regs_to_read[i]);
+ if (retval < 0)
+ return retval;
+ sd->firmware_id[i] = gspca_dev->usb_buf[0];
+ }
+ PDEBUG(D_PROBE, "firmware ID is %02x%02x%02x%02x%02x%02x",
+ sd->firmware_id[0],
+ sd->firmware_id[1],
+ sd->firmware_id[2],
+ sd->firmware_id[3],
+ sd->firmware_id[4],
+ sd->firmware_id[5]);
+ return 0;
+}
+
+static int jl2005c_stream_start_vga_lg
+ (struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval = -1;
+ static u8 instruction[][2] = {
+ {0x05, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x18},
+ {0x02, 0x00},
+ {0x01, 0x00},
+ {0x04, 0x52},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+ msleep(60);
+ retval = jl2005c_write2(gspca_dev, instruction[i]);
+ if (retval < 0)
+ return retval;
+ }
+ msleep(60);
+ return retval;
+}
+
+static int jl2005c_stream_start_vga_small(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval = -1;
+ static u8 instruction[][2] = {
+ {0x06, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x1a},
+ {0x02, 0x00},
+ {0x01, 0x00},
+ {0x04, 0x52},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+ msleep(60);
+ retval = jl2005c_write2(gspca_dev, instruction[i]);
+ if (retval < 0)
+ return retval;
+ }
+ msleep(60);
+ return retval;
+}
+
+static int jl2005c_stream_start_cif_lg(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval = -1;
+ static u8 instruction[][2] = {
+ {0x05, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x30},
+ {0x02, 0x00},
+ {0x01, 0x00},
+ {0x04, 0x42},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+ msleep(60);
+ retval = jl2005c_write2(gspca_dev, instruction[i]);
+ if (retval < 0)
+ return retval;
+ }
+ msleep(60);
+ return retval;
+}
+
+static int jl2005c_stream_start_cif_small(struct gspca_dev *gspca_dev)
+{
+ int i;
+ int retval = -1;
+ static u8 instruction[][2] = {
+ {0x06, 0x00},
+ {0x7c, 0x00},
+ {0x7d, 0x32},
+ {0x02, 0x00},
+ {0x01, 0x00},
+ {0x04, 0x42},
+ };
+
+ for (i = 0; i < ARRAY_SIZE(instruction); i++) {
+ msleep(60);
+ retval = jl2005c_write2(gspca_dev, instruction[i]);
+ if (retval < 0)
+ return retval;
+ }
+ msleep(60);
+ return retval;
+}
+
+
+static int jl2005c_stop(struct gspca_dev *gspca_dev)
+{
+ int retval;
+
+ retval = jl2005c_write_reg(gspca_dev, 0x07, 0x00);
+ return retval;
+}
+
+/* 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 jl2005c_dostream(struct work_struct *work)
+{
+ struct sd *dev = container_of(work, struct sd, work_struct);
+ struct gspca_dev *gspca_dev = &dev->gspca_dev;
+ int bytes_left = 0; /* bytes remaining in current frame. */
+ int data_len; /* size to use for the next read. */
+ int header_read = 0;
+ unsigned char header_sig[2] = {0x4a, 0x4c};
+ int act_len;
+ int packet_type;
+ int ret;
+ u8 *buffer;
+
+ buffer = kmalloc(JL2005C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
+ if (!buffer) {
+ pr_err("Couldn't allocate USB buffer\n");
+ goto quit_stream;
+ }
+
+ while (gspca_dev->present && gspca_dev->streaming) {
+ /* Check if this is a new frame. If so, start the frame first */
+ if (!header_read) {
+ mutex_lock(&gspca_dev->usb_lock);
+ ret = jl2005c_start_new_frame(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ if (ret < 0)
+ goto quit_stream;
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+ buffer, JL2005C_MAX_TRANSFER, &act_len,
+ JL2005C_DATA_TIMEOUT);
+ PDEBUG(D_PACK,
+ "Got %d bytes out of %d for header",
+ act_len, JL2005C_MAX_TRANSFER);
+ if (ret < 0 || act_len < JL2005C_MAX_TRANSFER)
+ goto quit_stream;
+ /* Check whether we actually got the first blodk */
+ if (memcmp(header_sig, buffer, 2) != 0) {
+ pr_err("First block is not the first block\n");
+ goto quit_stream;
+ }
+ /* total size to fetch is byte 7, times blocksize
+ * of which we already got act_len */
+ bytes_left = buffer[0x07] * dev->block_size - act_len;
+ PDEBUG(D_PACK, "bytes_left = 0x%x", bytes_left);
+ /* We keep the header. It has other information, too.*/
+ packet_type = FIRST_PACKET;
+ gspca_frame_add(gspca_dev, packet_type,
+ buffer, act_len);
+ header_read = 1;
+ }
+ while (bytes_left > 0 && gspca_dev->present) {
+ data_len = bytes_left > JL2005C_MAX_TRANSFER ?
+ JL2005C_MAX_TRANSFER : bytes_left;
+ ret = usb_bulk_msg(gspca_dev->dev,
+ usb_rcvbulkpipe(gspca_dev->dev, 0x82),
+ buffer, data_len, &act_len,
+ JL2005C_DATA_TIMEOUT);
+ if (ret < 0 || act_len < data_len)
+ goto quit_stream;
+ PDEBUG(D_PACK,
+ "Got %d bytes out of %d for frame",
+ data_len, bytes_left);
+ bytes_left -= data_len;
+ if (bytes_left == 0) {
+ packet_type = LAST_PACKET;
+ header_read = 0;
+ } else
+ packet_type = INTER_PACKET;
+ gspca_frame_add(gspca_dev, packet_type,
+ buffer, data_len);
+ }
+ }
+quit_stream:
+ if (gspca_dev->present) {
+ mutex_lock(&gspca_dev->usb_lock);
+ jl2005c_stop(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+ }
+ kfree(buffer);
+}
+
+
+
+
+/* This function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct cam *cam;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ cam = &gspca_dev->cam;
+ /* We don't use the buffer gspca allocates so make it small. */
+ cam->bulk_size = 64;
+ cam->bulk = 1;
+ /* For the rest, the camera needs to be detected */
+ jl2005c_get_firmware_id(gspca_dev);
+ /* Here are some known firmware IDs
+ * First some JL2005B cameras
+ * {0x41, 0x07, 0x04, 0x2c, 0xe8, 0xf2} Sakar KidzCam
+ * {0x45, 0x02, 0x08, 0xb9, 0x00, 0xd2} No-name JL2005B
+ * JL2005C cameras
+ * {0x01, 0x0c, 0x16, 0x10, 0xf8, 0xc8} Argus DC-1512
+ * {0x12, 0x04, 0x03, 0xc0, 0x00, 0xd8} ICarly
+ * {0x86, 0x08, 0x05, 0x02, 0x00, 0xd4} Jazz
+ *
+ * Based upon this scanty evidence, we can detect a CIF camera by
+ * testing byte 0 for 0x4x.
+ */
+ if ((sd->firmware_id[0] & 0xf0) == 0x40) {
+ cam->cam_mode = cif_mode;
+ cam->nmodes = ARRAY_SIZE(cif_mode);
+ sd->block_size = 0x80;
+ } else {
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+ sd->block_size = 0x200;
+ }
+
+ INIT_WORK(&sd->work_struct, jl2005c_dostream);
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+
+ struct sd *sd = (struct sd *) gspca_dev;
+ sd->cap_mode = gspca_dev->cam.cam_mode;
+
+ switch (gspca_dev->width) {
+ case 640:
+ PDEBUG(D_STREAM, "Start streaming at vga resolution");
+ jl2005c_stream_start_vga_lg(gspca_dev);
+ break;
+ case 320:
+ PDEBUG(D_STREAM, "Start streaming at qvga resolution");
+ jl2005c_stream_start_vga_small(gspca_dev);
+ break;
+ case 352:
+ PDEBUG(D_STREAM, "Start streaming at cif resolution");
+ jl2005c_stream_start_cif_lg(gspca_dev);
+ break;
+ case 176:
+ PDEBUG(D_STREAM, "Start streaming at qcif resolution");
+ jl2005c_stream_start_cif_small(gspca_dev);
+ break;
+ default:
+ pr_err("Unknown resolution specified\n");
+ return -1;
+ }
+
+ /* Start the workqueue function to do the streaming */
+ sd->work_thread = create_singlethread_workqueue(MODULE_NAME);
+ queue_work(sd->work_thread, &sd->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 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);
+}
+
+
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ /* .ctrls = none have been detected */
+ /* .nctrls = ARRAY_SIZE(sd_ctrls), */
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stop0 = sd_stop0,
+};
+
+/* -- module initialisation -- */
+static const __devinitdata struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0979, 0x0227)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- 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;
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/video/gspca/konica.c
index b1da7f4096c..f0c0d74dfe9 100644
--- a/drivers/media/video/gspca/konica.c
+++ b/drivers/media/video/gspca/konica.c
@@ -247,9 +247,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
gspca_dev->cam.cam_mode = vga_mode;
gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
gspca_dev->cam.no_urb_create = 1;
- /* The highest alt setting has an isoc packetsize of 0, so we
- don't want to use it */
- gspca_dev->nbalt--;
sd->brightness = BRIGHTNESS_DEFAULT;
sd->contrast = CONTRAST_DEFAULT;
diff --git a/drivers/media/video/gspca/m5602/Makefile b/drivers/media/video/gspca/m5602/Makefile
index 7f52961f439..575b75bacb6 100644
--- a/drivers/media/video/gspca/m5602/Makefile
+++ b/drivers/media/video/gspca/m5602/Makefile
@@ -8,4 +8,4 @@ gspca_m5602-objs := m5602_core.o \
m5602_s5k83a.o \
m5602_s5k4aa.o
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
index 9fe3816b2aa..0c449367543 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -27,8 +27,8 @@
/* Kernel module parameters */
int force_sensor;
-static int dump_bridge;
-int dump_sensor;
+static bool dump_bridge;
+bool dump_sensor;
static const struct usb_device_id m5602_table[] = {
{USB_DEVICE(0x0402, 0x5602)},
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
index b1f0c492036..8c672b5c8c6 100644
--- a/drivers/media/video/gspca/m5602/m5602_mt9m111.h
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
@@ -106,7 +106,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int mt9m111_probe(struct sd *sd);
int mt9m111_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/video/gspca/m5602/m5602_ov7660.h
index 2efd607987e..2b6a13b508f 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov7660.h
+++ b/drivers/media/video/gspca/m5602/m5602_ov7660.h
@@ -86,7 +86,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int ov7660_probe(struct sd *sd);
int ov7660_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/video/gspca/m5602/m5602_ov9650.h
index da9a129b739..f7aa5bf6898 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.h
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.h
@@ -135,7 +135,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int ov9650_probe(struct sd *sd);
int ov9650_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/video/gspca/m5602/m5602_po1030.h
index 33835959639..81a2bcb88fe 100644
--- a/drivers/media/video/gspca/m5602/m5602_po1030.h
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.h
@@ -147,7 +147,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int po1030_probe(struct sd *sd);
int po1030_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
index 8cc7a3f6da7..8e0035e731c 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
@@ -65,7 +65,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int s5k4aa_probe(struct sd *sd);
int s5k4aa_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
index 80a63a236e2..79952247b53 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.h
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
@@ -41,7 +41,7 @@
/* Kernel module parameters */
extern int force_sensor;
-extern int dump_sensor;
+extern bool dump_sensor;
int s5k83a_probe(struct sd *sd);
int s5k83a_init(struct sd *sd);
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index 5c2ea05c46b..b0231465afa 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -263,7 +263,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->nmodes = ARRAY_SIZE(vga_mode);
cam->ctrls = sd->ctrls;
sd->quality = QUALITY_DEF;
- gspca_dev->nbalt = 9; /* use the altsetting 08 */
return 0;
}
diff --git a/drivers/media/video/gspca/nw80x.c b/drivers/media/video/gspca/nw80x.c
index d4bec932177..7167cac7359 100644
--- a/drivers/media/video/gspca/nw80x.c
+++ b/drivers/media/video/gspca/nw80x.c
@@ -1763,8 +1763,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
if ((unsigned) webcam >= NWEBCAMS)
webcam = 0;
sd->webcam = webcam;
- gspca_dev->cam.reverse_alts = 1;
gspca_dev->cam.ctrls = sd->ctrls;
+ gspca_dev->cam.needs_full_bandwidth = 1;
sd->ag_cnt = -1;
/*
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index 08b8ce1dee1..739e8a2a2d3 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -3348,7 +3348,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
case BRIDGE_W9968CF:
cam->cam_mode = w9968cf_vga_mode;
cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode);
- cam->reverse_alts = 1;
break;
}
@@ -3684,8 +3683,8 @@ static void ov511_mode_init_regs(struct sd *sd)
/* Check if we have enough bandwidth to disable compression */
fps = (interlaced ? 60 : 30) / (sd->clockdiv + 1) + 1;
needed = fps * sd->gspca_dev.width * sd->gspca_dev.height * 3 / 2;
- /* 1400 is a conservative estimate of the max nr of isoc packets/sec */
- if (needed > 1400 * packet_size) {
+ /* 1000 isoc packets/sec */
+ if (needed > 1000 * packet_size) {
/* Enable Y and UV quantization and compression */
reg_w(sd, R511_COMP_EN, 0x07);
reg_w(sd, R511_COMP_LUT_EN, 0x03);
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c
index f30060d5063..e6601b88603 100644
--- a/drivers/media/video/gspca/ov534_9.c
+++ b/drivers/media/video/gspca/ov534_9.c
@@ -71,6 +71,7 @@ struct sd {
enum sensors {
SENSOR_OV965x, /* ov9657 */
SENSOR_OV971x, /* ov9712 */
+ SENSOR_OV562x, /* ov5621 */
NSENSORS
};
@@ -207,6 +208,14 @@ static const struct v4l2_pix_format ov971x_mode[] = {
}
};
+static const struct v4l2_pix_format ov562x_mode[] = {
+ {2592, 1680, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
+ .bytesperline = 2592,
+ .sizeimage = 2592 * 1680,
+ .colorspace = V4L2_COLORSPACE_SRGB
+ }
+};
+
static const u8 bridge_init[][2] = {
{0x88, 0xf8},
{0x89, 0xff},
@@ -830,6 +839,124 @@ static const u8 ov965x_start_2_sxga[][2] = {
{0xa3, 0x41}, /* bd60 */
};
+static const u8 ov562x_init[][2] = {
+ {0x88, 0x20},
+ {0x89, 0x0a},
+ {0x8a, 0x90},
+ {0x8b, 0x06},
+ {0x8c, 0x01},
+ {0x8d, 0x10},
+ {0x1c, 0x00},
+ {0x1d, 0x48},
+ {0x1d, 0x00},
+ {0x1d, 0xff},
+ {0x1c, 0x0a},
+ {0x1d, 0x2e},
+ {0x1d, 0x1e},
+};
+
+static const u8 ov562x_init_2[][2] = {
+ {0x12, 0x80},
+ {0x11, 0x41},
+ {0x13, 0x00},
+ {0x10, 0x1e},
+ {0x3b, 0x07},
+ {0x5b, 0x40},
+ {0x39, 0x07},
+ {0x53, 0x02},
+ {0x54, 0x60},
+ {0x04, 0x20},
+ {0x27, 0x04},
+ {0x3d, 0x40},
+ {0x36, 0x00},
+ {0xc5, 0x04},
+ {0x4e, 0x00},
+ {0x4f, 0x93},
+ {0x50, 0x7b},
+ {0xca, 0x0c},
+ {0xcb, 0x0f},
+ {0x39, 0x07},
+ {0x4a, 0x10},
+ {0x3e, 0x0a},
+ {0x3d, 0x00},
+ {0x0c, 0x38},
+ {0x38, 0x90},
+ {0x46, 0x30},
+ {0x4f, 0x93},
+ {0x50, 0x7b},
+ {0xab, 0x00},
+ {0xca, 0x0c},
+ {0xcb, 0x0f},
+ {0x37, 0x02},
+ {0x44, 0x48},
+ {0x8d, 0x44},
+ {0x2a, 0x00},
+ {0x2b, 0x00},
+ {0x32, 0x00},
+ {0x38, 0x90},
+ {0x53, 0x02},
+ {0x54, 0x60},
+ {0x12, 0x00},
+ {0x17, 0x12},
+ {0x18, 0xb4},
+ {0x19, 0x0c},
+ {0x1a, 0xf4},
+ {0x03, 0x4a},
+ {0x89, 0x20},
+ {0x83, 0x80},
+ {0xb7, 0x9d},
+ {0xb6, 0x11},
+ {0xb5, 0x55},
+ {0xb4, 0x00},
+ {0xa9, 0xf0},
+ {0xa8, 0x0a},
+ {0xb8, 0xf0},
+ {0xb9, 0xf0},
+ {0xba, 0xf0},
+ {0x81, 0x07},
+ {0x63, 0x44},
+ {0x13, 0xc7},
+ {0x14, 0x60},
+ {0x33, 0x75},
+ {0x2c, 0x00},
+ {0x09, 0x00},
+ {0x35, 0x30},
+ {0x27, 0x04},
+ {0x3c, 0x07},
+ {0x3a, 0x0a},
+ {0x3b, 0x07},
+ {0x01, 0x40},
+ {0x02, 0x40},
+ {0x16, 0x40},
+ {0x52, 0xb0},
+ {0x51, 0x83},
+ {0x21, 0xbb},
+ {0x22, 0x10},
+ {0x23, 0x03},
+ {0x35, 0x38},
+ {0x20, 0x90},
+ {0x28, 0x30},
+ {0x73, 0xe1},
+ {0x6c, 0x00},
+ {0x6d, 0x80},
+ {0x6e, 0x00},
+ {0x70, 0x04},
+ {0x71, 0x00},
+ {0x8d, 0x04},
+ {0x64, 0x00},
+ {0x65, 0x00},
+ {0x66, 0x00},
+ {0x67, 0x00},
+ {0x68, 0x00},
+ {0x69, 0x00},
+ {0x6a, 0x00},
+ {0x6b, 0x00},
+ {0x71, 0x94},
+ {0x74, 0x20},
+ {0x80, 0x09},
+ {0x85, 0xc0},
+};
+
static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val)
{
struct usb_device *udev = gspca_dev->dev;
@@ -980,16 +1107,34 @@ static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 val;
+ s8 sval;
if (gspca_dev->ctrl_dis & (1 << BRIGHTNESS))
return;
- val = sd->ctrls[BRIGHTNESS].val;
- if (val < 8)
- val = 15 - val; /* f .. 8 */
- else
- val = val - 8; /* 0 .. 7 */
- sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */
- 0x0f | (val << 4));
+ if (sd->sensor == SENSOR_OV562x) {
+ sval = sd->ctrls[BRIGHTNESS].val;
+ val = 0x76;
+ val += sval;
+ sccb_write(gspca_dev, 0x24, val);
+ val = 0x6a;
+ val += sval;
+ sccb_write(gspca_dev, 0x25, val);
+ if (sval < -40)
+ val = 0x71;
+ else if (sval < 20)
+ val = 0x94;
+ else
+ val = 0xe6;
+ sccb_write(gspca_dev, 0x26, val);
+ } else {
+ val = sd->ctrls[BRIGHTNESS].val;
+ if (val < 8)
+ val = 15 - val; /* f .. 8 */
+ else
+ val = val - 8; /* 0 .. 7 */
+ sccb_write(gspca_dev, 0x55, /* brtn - brightness adjustment */
+ 0x0f | (val << 4));
+ }
}
static void setcontrast(struct gspca_dev *gspca_dev)
@@ -1210,6 +1355,26 @@ static int sd_init(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x56, 0x1f);
else
reg_w(gspca_dev, 0x56, 0x17);
+ } else if ((sensor_id & 0xfff0) == 0x5620) {
+ sd->sensor = SENSOR_OV562x;
+ gspca_dev->ctrl_dis = (1 << CONTRAST) |
+ (1 << AUTOGAIN) |
+ (1 << EXPOSURE) |
+ (1 << SHARPNESS) |
+ (1 << SATUR) |
+ (1 << LIGHTFREQ);
+
+ sd->ctrls[BRIGHTNESS].min = -90;
+ sd->ctrls[BRIGHTNESS].max = 90;
+ sd->ctrls[BRIGHTNESS].def = 0;
+ gspca_dev->cam.cam_mode = ov562x_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(ov562x_mode);
+
+ reg_w_array(gspca_dev, ov562x_init,
+ ARRAY_SIZE(ov562x_init));
+ sccb_w_array(gspca_dev, ov562x_init_2,
+ ARRAY_SIZE(ov562x_init_2));
+ reg_w(gspca_dev, 0xe0, 0x00);
} else {
err("Unknown sensor %04x", sensor_id);
return -EINVAL;
@@ -1224,6 +1389,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
if (sd->sensor == SENSOR_OV971x)
return gspca_dev->usb_err;
+ else if (sd->sensor == SENSOR_OV562x) {
+ setbrightness(gspca_dev);
+ return gspca_dev->usb_err;
+ }
switch (gspca_dev->curr_mode) {
case QVGA_MODE: /* 320x240 */
sccb_w_array(gspca_dev, ov965x_start_1_vga,
@@ -1409,6 +1578,7 @@ static const struct sd_desc sd_desc = {
static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x05a9, 0x8065)},
{USB_DEVICE(0x06f8, 0x3003)},
+ {USB_DEVICE(0x05a9, 0x1550)},
{}
};
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index ece8b1e82a1..3844c49f269 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -41,14 +41,14 @@ MODULE_LICENSE("GPL");
#define PAC207_BRIGHTNESS_DEFAULT 46
#define PAC207_EXPOSURE_MIN 3
-#define PAC207_EXPOSURE_MAX 26
+#define PAC207_EXPOSURE_MAX 90 /* 1 sec expo time / 1 fps */
#define PAC207_EXPOSURE_DEFAULT 5 /* power on default: 3 */
-#define PAC207_EXPOSURE_KNEE 8 /* 4 = 30 fps, 11 = 8, 15 = 6 */
+#define PAC207_EXPOSURE_KNEE 9 /* fps: 90 / exposure -> 9: 10 fps */
#define PAC207_GAIN_MIN 0
#define PAC207_GAIN_MAX 31
-#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */
-#define PAC207_GAIN_KNEE 31
+#define PAC207_GAIN_DEFAULT 7 /* power on default: 9 */
+#define PAC207_GAIN_KNEE 15
#define PAC207_AUTOGAIN_DEADZONE 30
@@ -332,7 +332,7 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
if (sd->autogain_ignore_frames > 0)
sd->autogain_ignore_frames--;
else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum,
- 100, PAC207_AUTOGAIN_DEADZONE,
+ 90, PAC207_AUTOGAIN_DEADZONE,
PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE))
sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
}
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
index 2811195258c..30662fccb0c 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/video/gspca/pac7302.c
@@ -1,8 +1,8 @@
/*
- * Pixart PAC7302 library
- * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
+ * Pixart PAC7302 driver
*
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2008-2012 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
*
* Separated from Pixart PAC7311 library by MĂ¡rton NĂ©meth
* Camera button input handling by MĂ¡rton NĂ©meth <nm127@freemail.hu>
@@ -63,67 +63,61 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#define MODULE_NAME "pac7302"
-
#include <linux/input.h>
#include <media/v4l2-chip-ident.h>
#include "gspca.h"
+/* Include pac common sof detection functions */
+#include "pac_common.h"
-MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
+ "Thomas Kaiser thomas@kaiser-linux.li");
MODULE_DESCRIPTION("Pixart PAC7302");
MODULE_LICENSE("GPL");
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ COLORS,
+ WHITE_BALANCE,
+ RED_BALANCE,
+ BLUE_BALANCE,
+ GAIN,
+ AUTOGAIN,
+ EXPOSURE,
+ VFLIP,
+ HFLIP,
+ NCTRLS /* number of controls */
+};
+
/* specific webcam descriptor for pac7302 */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- unsigned char brightness;
- unsigned char contrast;
- unsigned char colors;
- unsigned char white_balance;
- unsigned char red_balance;
- unsigned char blue_balance;
- unsigned char gain;
- unsigned char autogain;
- unsigned short exposure;
- __u8 hflip;
- __u8 vflip;
+ struct gspca_ctrl ctrls[NCTRLS];
+
u8 flags;
#define FL_HFLIP 0x01 /* mirrored by default */
#define FL_VFLIP 0x02 /* vertical flipped by default */
u8 sof_read;
- u8 autogain_ignore_frames;
+ s8 autogain_ignore_frames;
atomic_t avg_lum;
};
/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static void setbrightcont(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setwhitebalance(struct gspca_dev *gspca_dev);
+static void setredbalance(struct gspca_dev *gspca_dev);
+static void setbluebalance(struct gspca_dev *gspca_dev);
+static void setgain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static void setautogain(struct gspca_dev *gspca_dev);
+static void sethvflip(struct gspca_dev *gspca_dev);
static const struct ctrl sd_ctrls[] = {
- {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -132,13 +126,11 @@ static const struct ctrl sd_ctrls[] = {
#define BRIGHTNESS_MAX 0x20
.maximum = BRIGHTNESS_MAX,
.step = 1,
-#define BRIGHTNESS_DEF 0x10
- .default_value = BRIGHTNESS_DEF,
+ .default_value = 0x10,
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set_control = setbrightcont
},
- {
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -147,13 +139,11 @@ static const struct ctrl sd_ctrls[] = {
#define CONTRAST_MAX 255
.maximum = CONTRAST_MAX,
.step = 1,
-#define CONTRAST_DEF 127
- .default_value = CONTRAST_DEF,
+ .default_value = 127,
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set_control = setbrightcont
},
- {
+[COLORS] = {
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -162,13 +152,11 @@ static const struct ctrl sd_ctrls[] = {
#define COLOR_MAX 255
.maximum = COLOR_MAX,
.step = 1,
-#define COLOR_DEF 127
- .default_value = COLOR_DEF,
+ .default_value = 127
},
- .set = sd_setcolors,
- .get = sd_getcolors,
+ .set_control = setcolors
},
- {
+[WHITE_BALANCE] = {
{
.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -176,13 +164,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define WHITEBALANCE_DEF 4
- .default_value = WHITEBALANCE_DEF,
+ .default_value = 4,
},
- .set = sd_setwhitebalance,
- .get = sd_getwhitebalance,
+ .set_control = setwhitebalance
},
- {
+[RED_BALANCE] = {
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -190,13 +176,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 3,
.step = 1,
-#define REDBALANCE_DEF 1
- .default_value = REDBALANCE_DEF,
+ .default_value = 1,
},
- .set = sd_setredbalance,
- .get = sd_getredbalance,
+ .set_control = setredbalance
},
- {
+[BLUE_BALANCE] = {
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -204,29 +188,25 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 3,
.step = 1,
-#define BLUEBALANCE_DEF 1
- .default_value = BLUEBALANCE_DEF,
+ .default_value = 1,
},
- .set = sd_setbluebalance,
- .get = sd_getbluebalance,
+ .set_control = setbluebalance
},
- {
+[GAIN] = {
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
.minimum = 0,
-#define GAIN_MAX 255
- .maximum = GAIN_MAX,
+ .maximum = 255,
.step = 1,
#define GAIN_DEF 127
#define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */
.default_value = GAIN_DEF,
},
- .set = sd_setgain,
- .get = sd_getgain,
+ .set_control = setgain
},
- {
+[EXPOSURE] = {
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -238,10 +218,9 @@ static const struct ctrl sd_ctrls[] = {
#define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */
.default_value = EXPOSURE_DEF,
},
- .set = sd_setexposure,
- .get = sd_getexposure,
+ .set_control = setexposure
},
- {
+[AUTOGAIN] = {
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -252,10 +231,9 @@ static const struct ctrl sd_ctrls[] = {
#define AUTOGAIN_DEF 1
.default_value = AUTOGAIN_DEF,
},
- .set = sd_setautogain,
- .get = sd_getautogain,
+ .set_control = setautogain,
},
- {
+[HFLIP] = {
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -263,13 +241,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define HFLIP_DEF 0
- .default_value = HFLIP_DEF,
+ .default_value = 0,
},
- .set = sd_sethflip,
- .get = sd_gethflip,
+ .set_control = sethvflip,
},
- {
+[VFLIP] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -277,11 +253,9 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define VFLIP_DEF 0
- .default_value = VFLIP_DEF,
+ .default_value = 0,
},
- .set = sd_setvflip,
- .get = sd_getvflip,
+ .set_control = sethvflip
},
};
@@ -290,21 +264,21 @@ static const struct v4l2_pix_format vga_mode[] = {
.bytesperline = 640,
.sizeimage = 640 * 480 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 0},
+ },
};
#define LOAD_PAGE3 255
#define END_OF_SEQUENCE 0
/* pac 7302 */
-static const __u8 init_7302[] = {
+static const u8 init_7302[] = {
/* index,value */
0xff, 0x01, /* page 1 */
0x78, 0x00, /* deactivate */
0xff, 0x01,
0x78, 0x40, /* led off */
};
-static const __u8 start_7302[] = {
+static const u8 start_7302[] = {
/* index, len, [value]* */
0xff, 1, 0x00, /* page 0 */
0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
@@ -319,7 +293,7 @@ static const __u8 start_7302[] = {
0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
0x00, 0x54, 0x11,
0x55, 1, 0x00,
- 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
+ 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
0x6b, 1, 0x00,
0x6e, 3, 0x08, 0x06, 0x00,
0x72, 3, 0x00, 0xff, 0x00,
@@ -370,7 +344,7 @@ static const __u8 start_7302[] = {
#define SKIP 0xaa
/* page 3 - the value SKIP says skip the index - see reg_w_page() */
-static const __u8 page3_7302[] = {
+static const u8 page3_7302[] = {
0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -394,7 +368,7 @@ static const __u8 page3_7302[] = {
};
static void reg_w_buf(struct gspca_dev *gspca_dev,
- __u8 index,
+ u8 index,
const u8 *buffer, int len)
{
int ret;
@@ -410,7 +384,7 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
index, gspca_dev->usb_buf, len,
500);
if (ret < 0) {
- pr_err("reg_w_buf failed index 0x%02x, error %d\n",
+ pr_err("reg_w_buf failed i: %02x error %d\n",
index, ret);
gspca_dev->usb_err = ret;
}
@@ -418,8 +392,8 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
static void reg_w(struct gspca_dev *gspca_dev,
- __u8 index,
- __u8 value)
+ u8 index,
+ u8 value)
{
int ret;
@@ -433,14 +407,14 @@ static void reg_w(struct gspca_dev *gspca_dev,
0, index, gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
+ pr_err("reg_w() failed i: %02x v: %02x error %d\n",
index, value, ret);
gspca_dev->usb_err = ret;
}
}
static void reg_w_seq(struct gspca_dev *gspca_dev,
- const __u8 *seq, int len)
+ const u8 *seq, int len)
{
while (--len >= 0) {
reg_w(gspca_dev, seq[0], seq[1]);
@@ -450,7 +424,7 @@ static void reg_w_seq(struct gspca_dev *gspca_dev,
/* load the beginning of a page */
static void reg_w_page(struct gspca_dev *gspca_dev,
- const __u8 *page, int len)
+ const u8 *page, int len)
{
int index;
int ret = 0;
@@ -468,7 +442,7 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
0, index, gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
+ pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
index, page[index], ret);
gspca_dev->usb_err = ret;
break;
@@ -478,8 +452,8 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
/* output a variable sequence */
static void reg_w_var(struct gspca_dev *gspca_dev,
- const __u8 *seq,
- const __u8 *page3, unsigned int page3_len)
+ const u8 *seq,
+ const u8 *page3, unsigned int page3_len)
{
int index, len;
@@ -493,11 +467,13 @@ static void reg_w_var(struct gspca_dev *gspca_dev,
reg_w_page(gspca_dev, page3, page3_len);
break;
default:
+#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
PDEBUG(D_ERR|D_STREAM,
"Incorrect variable sequence");
return;
}
+#endif
while (len > 0) {
if (len < 8) {
reg_w_buf(gspca_dev,
@@ -524,21 +500,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
- PDEBUG(D_CONF, "Find Sensor PAC7302");
cam->cam_mode = vga_mode; /* only 640x480 */
cam->nmodes = ARRAY_SIZE(vga_mode);
- sd->brightness = BRIGHTNESS_DEF;
- sd->contrast = CONTRAST_DEF;
- sd->colors = COLOR_DEF;
- sd->white_balance = WHITEBALANCE_DEF;
- sd->red_balance = REDBALANCE_DEF;
- sd->blue_balance = BLUEBALANCE_DEF;
- sd->gain = GAIN_DEF;
- sd->exposure = EXPOSURE_DEF;
- sd->autogain = AUTOGAIN_DEF;
- sd->hflip = HFLIP_DEF;
- sd->vflip = VFLIP_DEF;
+ gspca_dev->cam.ctrls = sd->ctrls;
+
sd->flags = id->driver_info;
return 0;
}
@@ -548,19 +514,19 @@ static void setbrightcont(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i, v;
- static const __u8 max[10] =
+ static const u8 max[10] =
{0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
0xd4, 0xec};
- static const __u8 delta[10] =
+ static const u8 delta[10] =
{0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
0x11, 0x0b};
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
for (i = 0; i < 10; i++) {
v = max[i];
- v += (sd->brightness - BRIGHTNESS_MAX)
+ v += (sd->ctrls[BRIGHTNESS].val - BRIGHTNESS_MAX)
* 150 / BRIGHTNESS_MAX; /* 200 ? */
- v -= delta[i] * sd->contrast / CONTRAST_MAX;
+ v -= delta[i] * sd->ctrls[CONTRAST].val / CONTRAST_MAX;
if (v < 0)
v = 0;
else if (v > 0xff)
@@ -584,12 +550,11 @@ static void setcolors(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x11, 0x01);
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
for (i = 0; i < 9; i++) {
- v = a[i] * sd->colors / COLOR_MAX + b[i];
+ v = a[i] * sd->ctrls[COLORS].val / COLOR_MAX + b[i];
reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
}
reg_w(gspca_dev, 0xdc, 0x01);
- PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors);
}
static void setwhitebalance(struct gspca_dev *gspca_dev)
@@ -597,10 +562,9 @@ static void setwhitebalance(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- reg_w(gspca_dev, 0xc6, sd->white_balance);
+ reg_w(gspca_dev, 0xc6, sd->ctrls[WHITE_BALANCE].val);
reg_w(gspca_dev, 0xdc, 0x01);
- PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance);
}
static void setredbalance(struct gspca_dev *gspca_dev)
@@ -608,10 +572,9 @@ static void setredbalance(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- reg_w(gspca_dev, 0xc5, sd->red_balance);
+ reg_w(gspca_dev, 0xc5, sd->ctrls[RED_BALANCE].val);
reg_w(gspca_dev, 0xdc, 0x01);
- PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance);
}
static void setbluebalance(struct gspca_dev *gspca_dev)
@@ -619,10 +582,9 @@ static void setbluebalance(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x00); /* page 0 */
- reg_w(gspca_dev, 0xc7, sd->blue_balance);
+ reg_w(gspca_dev, 0xc7, sd->ctrls[BLUE_BALANCE].val);
reg_w(gspca_dev, 0xdc, 0x01);
- PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance);
}
static void setgain(struct gspca_dev *gspca_dev)
@@ -630,7 +592,7 @@ static void setgain(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
reg_w(gspca_dev, 0xff, 0x03); /* page 3 */
- reg_w(gspca_dev, 0x10, sd->gain >> 3);
+ reg_w(gspca_dev, 0x10, sd->ctrls[GAIN].val >> 3);
/* load registers to sensor (Bit 0, auto clear) */
reg_w(gspca_dev, 0x11, 0x01);
@@ -639,13 +601,13 @@ static void setgain(struct gspca_dev *gspca_dev)
static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 clockdiv;
- __u16 exposure;
+ u8 clockdiv;
+ u16 exposure;
/* register 2 of frame 3 contains the clock divider configuring the
no fps according to the formula: 90 / reg. sd->exposure is the
desired exposure time in 0.5 ms. */
- clockdiv = (90 * sd->exposure + 1999) / 2000;
+ clockdiv = (90 * sd->ctrls[EXPOSURE].val + 1999) / 2000;
/* Note clockdiv = 3 also works, but when running at 30 fps, depending
on the scene being recorded, the camera switches to another
@@ -664,7 +626,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
/* frame exposure time in ms = 1000 * clockdiv / 90 ->
exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */
- exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv);
+ exposure = (sd->ctrls[EXPOSURE].val * 45 * 448) / (1000 * clockdiv);
/* 0 = use full frametime, 448 = no exposure, reverse it */
exposure = 448 - exposure;
@@ -677,15 +639,35 @@ static void setexposure(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x11, 0x01);
}
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* when switching to autogain set defaults to make sure
+ we are on a valid point of the autogain gain /
+ exposure knee graph, and give this change time to
+ take effect before doing autogain. */
+ if (sd->ctrls[AUTOGAIN].val) {
+ sd->ctrls[EXPOSURE].val = EXPOSURE_DEF;
+ sd->ctrls[GAIN].val = GAIN_DEF;
+ sd->autogain_ignore_frames =
+ PAC_AUTOGAIN_IGNORE_FRAMES;
+ } else {
+ sd->autogain_ignore_frames = -1;
+ }
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+}
+
static void sethvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 data, hflip, vflip;
- hflip = sd->hflip;
+ hflip = sd->ctrls[HFLIP].val;
if (sd->flags & FL_HFLIP)
hflip = !hflip;
- vflip = sd->vflip;
+ vflip = sd->ctrls[VFLIP].val;
if (sd->flags & FL_VFLIP)
vflip = !vflip;
@@ -708,8 +690,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->sof_read = 0;
-
reg_w_var(gspca_dev, start_7302,
page3_7302, sizeof(page3_7302));
setbrightcont(gspca_dev);
@@ -717,15 +697,13 @@ static int sd_start(struct gspca_dev *gspca_dev)
setwhitebalance(gspca_dev);
setredbalance(gspca_dev);
setbluebalance(gspca_dev);
- setgain(gspca_dev);
- setexposure(gspca_dev);
+ setautogain(gspca_dev);
sethvflip(gspca_dev);
/* only resolution 640x480 is supported for pac7302 */
sd->sof_read = 0;
- sd->autogain_ignore_frames = 0;
- atomic_set(&sd->avg_lum, -1);
+ atomic_set(&sd->avg_lum, 270 + sd->ctrls[BRIGHTNESS].val);
/* start stream */
reg_w(gspca_dev, 0xff, 0x01);
@@ -751,8 +729,10 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x78, 0x40);
}
-/* Include pac common sof detection functions */
-#include "pac_common.h"
+/* !! coarse_grained_expo_autogain is not used !! */
+#define exp_too_low_cnt flags
+#define exp_too_high_cnt sof_read
+#include "autogain_functions.h"
static void do_autogain(struct gspca_dev *gspca_dev)
{
@@ -761,65 +741,44 @@ static void do_autogain(struct gspca_dev *gspca_dev)
int desired_lum;
const int deadzone = 30;
- if (avg_lum == -1)
+ if (sd->autogain_ignore_frames < 0)
return;
- desired_lum = 270 + sd->brightness;
-
- if (sd->autogain_ignore_frames > 0)
+ if (sd->autogain_ignore_frames > 0) {
sd->autogain_ignore_frames--;
- else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
- deadzone, GAIN_KNEE, EXPOSURE_KNEE))
+ } else {
+ desired_lum = 270 + sd->ctrls[BRIGHTNESS].val;
+
+ auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
+ deadzone, GAIN_KNEE, EXPOSURE_KNEE);
sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
+ }
}
-/* JPEG header, part 1 */
-static const unsigned char pac_jpeg_header1[] = {
- 0xff, 0xd8, /* SOI: Start of Image */
-
- 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
- 0x00, 0x11, /* length = 17 bytes (including this length field) */
- 0x08 /* Precision: 8 */
- /* 2 bytes is placed here: number of image lines */
- /* 2 bytes is placed here: samples per line */
-};
-
-/* JPEG header, continued */
-static const unsigned char pac_jpeg_header2[] = {
- 0x03, /* Number of image components: 3 */
- 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
- 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
- 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
-
- 0xff, 0xda, /* SOS: Start Of Scan */
- 0x00, 0x0c, /* length = 12 bytes (including this length field) */
- 0x03, /* number of components: 3 */
- 0x01, 0x00, /* selector 1, table 0x00 */
- 0x02, 0x11, /* selector 2, table 0x11 */
- 0x03, 0x11, /* selector 3, table 0x11 */
- 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
- 0x00 /* Successive approximation: 0 */
+/* JPEG header */
+static const u8 jpeg_header[] = {
+ 0xff, 0xd8, /* SOI: Start of Image */
+
+ 0xff, 0xc0, /* SOF0: Start of Frame (Baseline DCT) */
+ 0x00, 0x11, /* length = 17 bytes (including this length field) */
+ 0x08, /* Precision: 8 */
+ 0x02, 0x80, /* height = 640 (image rotated) */
+ 0x01, 0xe0, /* width = 480 */
+ 0x03, /* Number of image components: 3 */
+ 0x01, 0x21, 0x00, /* ID=1, Subsampling 1x1, Quantization table: 0 */
+ 0x02, 0x11, 0x01, /* ID=2, Subsampling 2x1, Quantization table: 1 */
+ 0x03, 0x11, 0x01, /* ID=3, Subsampling 2x1, Quantization table: 1 */
+
+ 0xff, 0xda, /* SOS: Start Of Scan */
+ 0x00, 0x0c, /* length = 12 bytes (including this length field) */
+ 0x03, /* number of components: 3 */
+ 0x01, 0x00, /* selector 1, table 0x00 */
+ 0x02, 0x11, /* selector 2, table 0x11 */
+ 0x03, 0x11, /* selector 3, table 0x11 */
+ 0x00, 0x3f, /* Spectral selection: 0 .. 63 */
+ 0x00 /* Successive approximation: 0 */
};
-static void pac_start_frame(struct gspca_dev *gspca_dev,
- __u16 lines, __u16 samples_per_line)
-{
- unsigned char tmpbuf[4];
-
- gspca_frame_add(gspca_dev, FIRST_PACKET,
- pac_jpeg_header1, sizeof(pac_jpeg_header1));
-
- tmpbuf[0] = lines >> 8;
- tmpbuf[1] = lines & 0xff;
- tmpbuf[2] = samples_per_line >> 8;
- tmpbuf[3] = samples_per_line & 0xff;
-
- gspca_frame_add(gspca_dev, INTER_PACKET,
- tmpbuf, sizeof(tmpbuf));
- gspca_frame_add(gspca_dev, INTER_PACKET,
- pac_jpeg_header2, sizeof(pac_jpeg_header2));
-}
-
/* this function is run at interrupt level */
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
@@ -827,7 +786,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
u8 *image;
- unsigned char *sof;
+ u8 *sof;
sof = pac_find_sof(&sd->sof_read, data, len);
if (sof) {
@@ -864,234 +823,21 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
n >= lum_offset)
atomic_set(&sd->avg_lum, data[-lum_offset] +
data[-lum_offset + 1]);
- else
- atomic_set(&sd->avg_lum, -1);
/* Start the new frame with the jpeg header */
/* The PAC7302 has the image rotated 90 degrees */
- pac_start_frame(gspca_dev,
- gspca_dev->width, gspca_dev->height);
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ jpeg_header, sizeof jpeg_header);
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->brightness = val;
- if (gspca_dev->streaming)
- setbrightcont(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->brightness;
- return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->contrast = val;
- if (gspca_dev->streaming)
- setbrightcont(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->contrast;
- return 0;
-}
-
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->colors = val;
- if (gspca_dev->streaming)
- setcolors(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->colors;
- return 0;
-}
-
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->white_balance = val;
- if (gspca_dev->streaming)
- setwhitebalance(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->white_balance;
- return 0;
-}
-
-static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->red_balance = val;
- if (gspca_dev->streaming)
- setredbalance(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->red_balance;
- return 0;
-}
-
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->blue_balance = val;
- if (gspca_dev->streaming)
- setbluebalance(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->blue_balance;
- return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gain = val;
- if (gspca_dev->streaming)
- setgain(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->gain;
- return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->exposure = val;
- if (gspca_dev->streaming)
- setexposure(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->exposure;
- return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->autogain = val;
- /* when switching to autogain set defaults to make sure
- we are on a valid point of the autogain gain /
- exposure knee graph, and give this change time to
- take effect before doing autogain. */
- if (sd->autogain) {
- sd->exposure = EXPOSURE_DEF;
- sd->gain = GAIN_DEF;
- if (gspca_dev->streaming) {
- sd->autogain_ignore_frames =
- PAC_AUTOGAIN_IGNORE_FRAMES;
- setexposure(gspca_dev);
- setgain(gspca_dev);
- }
- }
-
- return gspca_dev->usb_err;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->autogain;
- return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->hflip = val;
- if (gspca_dev->streaming)
- sethvflip(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->hflip;
- return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->vflip = val;
- if (gspca_dev->streaming)
- sethvflip(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->vflip;
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
struct v4l2_dbg_register *reg)
{
- __u8 index;
- __u8 value;
+ u8 index;
+ u8 value;
/* reg->reg: bit0..15: reserved for register index (wIndex is 16bit
long on the USB bus)
@@ -1103,8 +849,8 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
) {
/* Currently writing to page 0 is only supported. */
/* reg_w() only supports 8bit index */
- index = reg->reg & 0x000000ff;
- value = reg->val & 0x000000ff;
+ index = reg->reg;
+ value = reg->val;
/* Note that there shall be no access to other page
by any other function between the page swith and
@@ -1165,7 +911,7 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
/* sub-driver description for pac7302 */
static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
@@ -1187,6 +933,7 @@ static const struct sd_desc sd_desc = {
/* -- module initialisation -- */
static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x06f8, 0x3009)},
+ {USB_DEVICE(0x06f8, 0x301b)},
{USB_DEVICE(0x093a, 0x2620)},
{USB_DEVICE(0x093a, 0x2621)},
{USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
@@ -1197,6 +944,7 @@ static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
{USB_DEVICE(0x093a, 0x262a)},
{USB_DEVICE(0x093a, 0x262c)},
+ {USB_DEVICE(0x145f, 0x013c)},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
@@ -1210,7 +958,7 @@ static int sd_probe(struct usb_interface *intf,
}
static struct usb_driver sd_driver = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
diff --git a/drivers/media/video/gspca/se401.c b/drivers/media/video/gspca/se401.c
index 1494e1829d3..bb70092c222 100644
--- a/drivers/media/video/gspca/se401.c
+++ b/drivers/media/video/gspca/se401.c
@@ -376,7 +376,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->bulk_size = BULK_SIZE;
cam->bulk_nurbs = 4;
cam->ctrls = sd->ctrls;
- gspca_dev->nbalt = 1; /* Ignore the bogus isoc alt settings */
sd->resetlevel = 0x2d; /* Set initial resetlevel */
/* See if the camera supports brightness */
@@ -395,6 +394,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
return 0;
}
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ gspca_dev->alt = 1; /* Ignore the bogus isoc alt settings */
+
+ return gspca_dev->usb_err;
+}
+
/* -- start the camera -- */
static int sd_start(struct gspca_dev *gspca_dev)
{
@@ -714,6 +721,7 @@ static const struct sd_desc sd_desc = {
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
+ .isoc_init = sd_isoc_init,
.start = sd_start,
.stopN = sd_stopN,
.dq_callback = sd_dq_callback,
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 33cabc342dc..7e71aa2d252 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -1,5 +1,7 @@
/*
* Sonix sn9c201 sn9c202 library
+ *
+ * Copyright (C) 2012 Jean-Francois Moine <http://moinejf.free.fr>
* Copyright (C) 2008-2009 microdia project <microdia@googlegroups.com>
* Copyright (C) 2009 Brian Johnson <brijohn@gmail.com>
*
@@ -33,8 +35,6 @@ MODULE_AUTHOR("Brian Johnson <brijohn@gmail.com>, "
MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver");
MODULE_LICENSE("GPL");
-#define MODULE_NAME "sn9c20x"
-
/*
* Pixel format private data
*/
@@ -66,10 +66,37 @@ MODULE_LICENSE("GPL");
#define LED_REVERSE 0x2 /* some cameras unset gpio to turn on leds */
#define FLIP_DETECT 0x4
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ SATURATION,
+ HUE,
+ GAMMA,
+ BLUE,
+ RED,
+ VFLIP,
+ HFLIP,
+ EXPOSURE,
+ GAIN,
+ AUTOGAIN,
+ QUALITY,
+ NCTRLS /* number of controls */
+};
+
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev;
+ struct gspca_ctrl ctrls[NCTRLS];
+
+ struct work_struct work;
+ struct workqueue_struct *work_thread;
+
+ u32 pktsz; /* (used by pkt_scan) */
+ u16 npkt;
+ s8 nchg;
+ u8 fmt; /* (used for JPEG QTAB update */
+
#define MIN_AVG_LUM 80
#define MAX_AVG_LUM 130
atomic_t avg_lum;
@@ -77,31 +104,18 @@ struct sd {
u8 older_step;
u8 exposure_step;
- u8 brightness;
- u8 contrast;
- u8 saturation;
- s16 hue;
- u8 gamma;
- u8 red;
- u8 blue;
-
- u8 hflip;
- u8 vflip;
- u8 gain;
- u16 exposure;
- u8 auto_exposure;
-
u8 i2c_addr;
u8 sensor;
u8 hstart;
u8 vstart;
u8 jpeg_hdr[JPEG_HDR_SZ];
- u8 quality;
u8 flags;
};
+static void qual_upd(struct work_struct *work);
+
struct i2c_reg_u8 {
u8 reg;
u8 val;
@@ -112,31 +126,6 @@ struct i2c_reg_u16 {
u16 val;
};
-static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_sethue(struct gspca_dev *gspca_dev, s32 val);
-static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val);
-static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setgain(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val);
-static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val);
-static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val);
-
static const struct dmi_system_id flip_dmi_table[] = {
{
.ident = "MSI MS-1034",
@@ -177,9 +166,16 @@ static const struct dmi_system_id flip_dmi_table[] = {
{}
};
-static const struct ctrl sd_ctrls[] = {
- {
-#define BRIGHTNESS_IDX 0
+static void set_cmatrix(struct gspca_dev *gspca_dev);
+static void set_gamma(struct gspca_dev *gspca_dev);
+static void set_redblue(struct gspca_dev *gspca_dev);
+static void set_hvflip(struct gspca_dev *gspca_dev);
+static void set_exposure(struct gspca_dev *gspca_dev);
+static void set_gain(struct gspca_dev *gspca_dev);
+static void set_quality(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -187,14 +183,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define BRIGHTNESS_DEFAULT 0x7f
- .default_value = BRIGHTNESS_DEFAULT,
+ .default_value = 0x7f
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set_control = set_cmatrix
},
- {
-#define CONTRAST_IDX 1
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -202,14 +195,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define CONTRAST_DEFAULT 0x7f
- .default_value = CONTRAST_DEFAULT,
+ .default_value = 0x7f
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set_control = set_cmatrix
},
- {
-#define SATURATION_IDX 2
+[SATURATION] = {
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -217,14 +207,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define SATURATION_DEFAULT 0x7f
- .default_value = SATURATION_DEFAULT,
+ .default_value = 0x7f
},
- .set = sd_setsaturation,
- .get = sd_getsaturation,
+ .set_control = set_cmatrix
},
- {
-#define HUE_IDX 3
+[HUE] = {
{
.id = V4L2_CID_HUE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -232,14 +219,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = -180,
.maximum = 180,
.step = 1,
-#define HUE_DEFAULT 0
- .default_value = HUE_DEFAULT,
+ .default_value = 0
},
- .set = sd_sethue,
- .get = sd_gethue,
+ .set_control = set_cmatrix
},
- {
-#define GAMMA_IDX 4
+[GAMMA] = {
{
.id = V4L2_CID_GAMMA,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -247,14 +231,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0xff,
.step = 1,
-#define GAMMA_DEFAULT 0x10
- .default_value = GAMMA_DEFAULT,
+ .default_value = 0x10
},
- .set = sd_setgamma,
- .get = sd_getgamma,
+ .set_control = set_gamma
},
- {
-#define BLUE_IDX 5
+[BLUE] = {
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -262,14 +243,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0x7f,
.step = 1,
-#define BLUE_DEFAULT 0x28
- .default_value = BLUE_DEFAULT,
+ .default_value = 0x28
},
- .set = sd_setbluebalance,
- .get = sd_getbluebalance,
+ .set_control = set_redblue
},
- {
-#define RED_IDX 6
+[RED] = {
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -277,14 +255,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0x7f,
.step = 1,
-#define RED_DEFAULT 0x28
- .default_value = RED_DEFAULT,
+ .default_value = 0x28
},
- .set = sd_setredbalance,
- .get = sd_getredbalance,
+ .set_control = set_redblue
},
- {
-#define HFLIP_IDX 7
+[HFLIP] = {
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -292,14 +267,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define HFLIP_DEFAULT 0
- .default_value = HFLIP_DEFAULT,
+ .default_value = 0,
},
- .set = sd_sethflip,
- .get = sd_gethflip,
+ .set_control = set_hvflip
},
- {
-#define VFLIP_IDX 8
+[VFLIP] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -307,14 +279,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define VFLIP_DEFAULT 0
- .default_value = VFLIP_DEFAULT,
+ .default_value = 0,
},
- .set = sd_setvflip,
- .get = sd_getvflip,
+ .set_control = set_hvflip
},
- {
-#define EXPOSURE_IDX 9
+[EXPOSURE] = {
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -322,14 +291,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 0x1780,
.step = 1,
-#define EXPOSURE_DEFAULT 0x33
- .default_value = EXPOSURE_DEFAULT,
+ .default_value = 0x33,
},
- .set = sd_setexposure,
- .get = sd_getexposure,
+ .set_control = set_exposure
},
- {
-#define GAIN_IDX 10
+[GAIN] = {
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -337,14 +303,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 28,
.step = 1,
-#define GAIN_DEFAULT 0x00
- .default_value = GAIN_DEFAULT,
+ .default_value = 0,
},
- .set = sd_setgain,
- .get = sd_getgain,
+ .set_control = set_gain
},
- {
-#define AUTOGAIN_IDX 11
+[AUTOGAIN] = {
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -352,11 +315,23 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define AUTO_EXPOSURE_DEFAULT 1
- .default_value = AUTO_EXPOSURE_DEFAULT,
+ .default_value = 1,
+ },
+ },
+[QUALITY] = {
+ {
+ .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Compression Quality",
+#define QUALITY_MIN 50
+#define QUALITY_MAX 90
+#define QUALITY_DEF 80
+ .minimum = QUALITY_MIN,
+ .maximum = QUALITY_MAX,
+ .step = 1,
+ .default_value = QUALITY_DEF,
},
- .set = sd_setautoexposure,
- .get = sd_getautoexposure,
+ .set_control = set_quality
},
};
@@ -876,7 +851,7 @@ static u8 hv7131r_gain[] = {
};
static struct i2c_reg_u8 soi968_init[] = {
- {0x12, 0x80}, {0x0c, 0x00}, {0x0f, 0x1f},
+ {0x0c, 0x00}, {0x0f, 0x1f},
{0x11, 0x80}, {0x38, 0x52}, {0x1e, 0x00},
{0x33, 0x08}, {0x35, 0x8c}, {0x36, 0x0c},
{0x37, 0x04}, {0x45, 0x04}, {0x47, 0xff},
@@ -902,7 +877,7 @@ static struct i2c_reg_u8 ov7660_init[] = {
};
static struct i2c_reg_u8 ov7670_init[] = {
- {0x12, 0x80}, {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
+ {0x11, 0x80}, {0x3a, 0x04}, {0x12, 0x01},
{0x32, 0xb6}, {0x03, 0x0a}, {0x0c, 0x00}, {0x3e, 0x00},
{0x70, 0x3a}, {0x71, 0x35}, {0x72, 0x11}, {0x73, 0xf0},
{0xa2, 0x02}, {0x13, 0xe0}, {0x00, 0x00}, {0x10, 0x00},
@@ -959,7 +934,7 @@ static struct i2c_reg_u8 ov7670_init[] = {
};
static struct i2c_reg_u8 ov9650_init[] = {
- {0x12, 0x80}, {0x00, 0x00}, {0x01, 0x78},
+ {0x00, 0x00}, {0x01, 0x78},
{0x02, 0x78}, {0x03, 0x36}, {0x04, 0x03},
{0x05, 0x00}, {0x06, 0x00}, {0x08, 0x00},
{0x09, 0x01}, {0x0c, 0x00}, {0x0d, 0x00},
@@ -989,7 +964,7 @@ static struct i2c_reg_u8 ov9650_init[] = {
};
static struct i2c_reg_u8 ov9655_init[] = {
- {0x12, 0x80}, {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
+ {0x0e, 0x61}, {0x11, 0x80}, {0x13, 0xba},
{0x14, 0x2e}, {0x16, 0x24}, {0x1e, 0x04}, {0x27, 0x08},
{0x28, 0x08}, {0x29, 0x15}, {0x2c, 0x08}, {0x34, 0x3d},
{0x35, 0x00}, {0x38, 0x12}, {0x0f, 0x42}, {0x39, 0x57},
@@ -1112,10 +1087,13 @@ static struct i2c_reg_u8 hv7131r_init[] = {
{0x23, 0x09}, {0x01, 0x08},
};
-static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
+static void reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
{
struct usb_device *dev = gspca_dev->dev;
int result;
+
+ if (gspca_dev->usb_err < 0)
+ return;
result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
0x00,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1125,17 +1103,19 @@ static int reg_r(struct gspca_dev *gspca_dev, u16 reg, u16 length)
length,
500);
if (unlikely(result < 0 || result != length)) {
- pr_err("Read register failed 0x%02X\n", reg);
- return -EIO;
+ pr_err("Read register %02x failed %d\n", reg, result);
+ gspca_dev->usb_err = result;
}
- return 0;
}
-static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
+static void reg_w(struct gspca_dev *gspca_dev, u16 reg,
const u8 *buffer, int length)
{
struct usb_device *dev = gspca_dev->dev;
int result;
+
+ if (gspca_dev->usb_err < 0)
+ return;
memcpy(gspca_dev->usb_buf, buffer, length);
result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
0x08,
@@ -1146,38 +1126,41 @@ static int reg_w(struct gspca_dev *gspca_dev, u16 reg,
length,
500);
if (unlikely(result < 0 || result != length)) {
- pr_err("Write register failed index 0x%02X\n", reg);
- return -EIO;
+ pr_err("Write register %02x failed %d\n", reg, result);
+ gspca_dev->usb_err = result;
}
- return 0;
}
-static int reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
+static void reg_w1(struct gspca_dev *gspca_dev, u16 reg, const u8 value)
{
- u8 data[1] = {value};
- return reg_w(gspca_dev, reg, data, 1);
+ reg_w(gspca_dev, reg, &value, 1);
}
-static int i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
+static void i2c_w(struct gspca_dev *gspca_dev, const u8 *buffer)
{
int i;
+
reg_w(gspca_dev, 0x10c0, buffer, 8);
for (i = 0; i < 5; i++) {
reg_r(gspca_dev, 0x10c0, 1);
+ if (gspca_dev->usb_err < 0)
+ return;
if (gspca_dev->usb_buf[0] & 0x04) {
- if (gspca_dev->usb_buf[0] & 0x08)
- return -EIO;
- return 0;
+ if (gspca_dev->usb_buf[0] & 0x08) {
+ pr_err("i2c_w error\n");
+ gspca_dev->usb_err = -EIO;
+ }
+ return;
}
- msleep(1);
+ msleep(10);
}
- return -EIO;
+ pr_err("i2c_w reg %02x no response\n", buffer[2]);
+/* gspca_dev->usb_err = -EIO; fixme: may occur */
}
-static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
+static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
{
struct sd *sd = (struct sd *) gspca_dev;
-
u8 row[8];
/*
@@ -1193,10 +1176,19 @@ static int i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
row[6] = 0x00;
row[7] = 0x10;
- return i2c_w(gspca_dev, row);
+ i2c_w(gspca_dev, row);
+}
+
+static void i2c_w1_buf(struct gspca_dev *gspca_dev,
+ struct i2c_reg_u8 *buf, int sz)
+{
+ while (--sz >= 0) {
+ i2c_w1(gspca_dev, buf->reg, buf->val);
+ buf++;
+ }
}
-static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
+static void i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
@@ -1208,16 +1200,25 @@ static int i2c_w2(struct gspca_dev *gspca_dev, u8 reg, u16 val)
row[0] = 0x81 | (3 << 4);
row[1] = sd->i2c_addr;
row[2] = reg;
- row[3] = (val >> 8) & 0xff;
- row[4] = val & 0xff;
+ row[3] = val >> 8;
+ row[4] = val;
row[5] = 0x00;
row[6] = 0x00;
row[7] = 0x10;
- return i2c_w(gspca_dev, row);
+ i2c_w(gspca_dev, row);
}
-static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
+static void i2c_w2_buf(struct gspca_dev *gspca_dev,
+ struct i2c_reg_u16 *buf, int sz)
+{
+ while (--sz >= 0) {
+ i2c_w2(gspca_dev, buf->reg, buf->val);
+ buf++;
+ }
+}
+
+static void i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
@@ -1230,19 +1231,15 @@ static int i2c_r1(struct gspca_dev *gspca_dev, u8 reg, u8 *val)
row[5] = 0;
row[6] = 0;
row[7] = 0x10;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
row[0] = 0x81 | (1 << 4) | 0x02;
row[2] = 0;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
- if (reg_r(gspca_dev, 0x10c2, 5) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
+ reg_r(gspca_dev, 0x10c2, 5);
*val = gspca_dev->usb_buf[4];
- return 0;
}
-static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
+static void i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 row[8];
@@ -1255,233 +1252,204 @@ static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
row[5] = 0;
row[6] = 0;
row[7] = 0x10;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
row[0] = 0x81 | (2 << 4) | 0x02;
row[2] = 0;
- if (i2c_w(gspca_dev, row) < 0)
- return -EIO;
- if (reg_r(gspca_dev, 0x10c2, 5) < 0)
- return -EIO;
+ i2c_w(gspca_dev, row);
+ reg_r(gspca_dev, 0x10c2, 5);
*val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
- return 0;
}
-static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
+static void ov9650_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
u16 id;
struct sd *sd = (struct sd *) gspca_dev;
- if (i2c_r2(gspca_dev, 0x1c, &id) < 0)
- return -EINVAL;
+ i2c_r2(gspca_dev, 0x1c, &id);
+ if (gspca_dev->usb_err < 0)
+ return;
if (id != 0x7fa2) {
pr_err("sensor id for ov9650 doesn't match (0x%04x)\n", id);
- return -ENODEV;
+ gspca_dev->usb_err = -ENODEV;
+ return;
}
- for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
- if (i2c_w1(gspca_dev, ov9650_init[i].reg,
- ov9650_init[i].val) < 0) {
- pr_err("OV9650 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov9650_init, ARRAY_SIZE(ov9650_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV9650 sensor initialization failed\n");
sd->hstart = 1;
sd->vstart = 7;
- return 0;
}
-static int ov9655_init_sensor(struct gspca_dev *gspca_dev)
+static void ov9655_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(ov9655_init); i++) {
- if (i2c_w1(gspca_dev, ov9655_init[i].reg,
- ov9655_init[i].val) < 0) {
- pr_err("OV9655 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov9655_init, ARRAY_SIZE(ov9655_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV9655 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 1;
sd->vstart = 2;
- return 0;
}
-static int soi968_init_sensor(struct gspca_dev *gspca_dev)
+static void soi968_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(soi968_init); i++) {
- if (i2c_w1(gspca_dev, soi968_init[i].reg,
- soi968_init[i].val) < 0) {
- pr_err("SOI968 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, soi968_init, ARRAY_SIZE(soi968_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("SOI968 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX)
- | (1 << EXPOSURE_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP)
+ | (1 << EXPOSURE);
sd->hstart = 60;
sd->vstart = 11;
- return 0;
}
-static int ov7660_init_sensor(struct gspca_dev *gspca_dev)
+static void ov7660_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(ov7660_init); i++) {
- if (i2c_w1(gspca_dev, ov7660_init[i].reg,
- ov7660_init[i].val) < 0) {
- pr_err("OV7660 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov7660_init, ARRAY_SIZE(ov7660_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV7660 sensor initialization failed\n");
sd->hstart = 3;
sd->vstart = 3;
- return 0;
}
-static int ov7670_init_sensor(struct gspca_dev *gspca_dev)
+static void ov7670_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(ov7670_init); i++) {
- if (i2c_w1(gspca_dev, ov7670_init[i].reg,
- ov7670_init[i].val) < 0) {
- pr_err("OV7670 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1(gspca_dev, 0x12, 0x80); /* sensor reset */
+ msleep(200);
+ i2c_w1_buf(gspca_dev, ov7670_init, ARRAY_SIZE(ov7670_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("OV7670 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 0;
sd->vstart = 1;
- return 0;
}
-static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9v_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
u16 value;
- int ret;
sd->i2c_addr = 0x5d;
- ret = i2c_r2(gspca_dev, 0xff, &value);
- if ((ret == 0) && (value == 0x8243)) {
- for (i = 0; i < ARRAY_SIZE(mt9v011_init); i++) {
- if (i2c_w2(gspca_dev, mt9v011_init[i].reg,
- mt9v011_init[i].val) < 0) {
- pr_err("MT9V011 sensor initialization failed\n");
- return -ENODEV;
- }
+ i2c_r2(gspca_dev, 0xff, &value);
+ if (gspca_dev->usb_err >= 0
+ && value == 0x8243) {
+ i2c_w2_buf(gspca_dev, mt9v011_init, ARRAY_SIZE(mt9v011_init));
+ if (gspca_dev->usb_err < 0) {
+ pr_err("MT9V011 sensor initialization failed\n");
+ return;
}
sd->hstart = 2;
sd->vstart = 2;
sd->sensor = SENSOR_MT9V011;
pr_info("MT9V011 sensor detected\n");
- return 0;
+ return;
}
+ gspca_dev->usb_err = 0;
sd->i2c_addr = 0x5c;
i2c_w2(gspca_dev, 0x01, 0x0004);
- ret = i2c_r2(gspca_dev, 0xff, &value);
- if ((ret == 0) && (value == 0x823a)) {
- for (i = 0; i < ARRAY_SIZE(mt9v111_init); i++) {
- if (i2c_w2(gspca_dev, mt9v111_init[i].reg,
- mt9v111_init[i].val) < 0) {
- pr_err("MT9V111 sensor initialization failed\n");
- return -ENODEV;
- }
+ i2c_r2(gspca_dev, 0xff, &value);
+ if (gspca_dev->usb_err >= 0
+ && value == 0x823a) {
+ i2c_w2_buf(gspca_dev, mt9v111_init, ARRAY_SIZE(mt9v111_init));
+ if (gspca_dev->usb_err < 0) {
+ pr_err("MT9V111 sensor initialization failed\n");
+ return;
}
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX)
- | (1 << AUTOGAIN_IDX)
- | (1 << GAIN_IDX);
+ gspca_dev->ctrl_dis = (1 << EXPOSURE)
+ | (1 << AUTOGAIN)
+ | (1 << GAIN);
sd->hstart = 2;
sd->vstart = 2;
sd->sensor = SENSOR_MT9V111;
pr_info("MT9V111 sensor detected\n");
- return 0;
+ return;
}
+ gspca_dev->usb_err = 0;
sd->i2c_addr = 0x5d;
- ret = i2c_w2(gspca_dev, 0xf0, 0x0000);
- if (ret < 0) {
+ i2c_w2(gspca_dev, 0xf0, 0x0000);
+ if (gspca_dev->usb_err < 0) {
+ gspca_dev->usb_err = 0;
sd->i2c_addr = 0x48;
i2c_w2(gspca_dev, 0xf0, 0x0000);
}
- ret = i2c_r2(gspca_dev, 0x00, &value);
- if ((ret == 0) && (value == 0x1229)) {
- for (i = 0; i < ARRAY_SIZE(mt9v112_init); i++) {
- if (i2c_w2(gspca_dev, mt9v112_init[i].reg,
- mt9v112_init[i].val) < 0) {
- pr_err("MT9V112 sensor initialization failed\n");
- return -ENODEV;
- }
+ i2c_r2(gspca_dev, 0x00, &value);
+ if (gspca_dev->usb_err >= 0
+ && value == 0x1229) {
+ i2c_w2_buf(gspca_dev, mt9v112_init, ARRAY_SIZE(mt9v112_init));
+ if (gspca_dev->usb_err < 0) {
+ pr_err("MT9V112 sensor initialization failed\n");
+ return;
}
sd->hstart = 6;
sd->vstart = 2;
sd->sensor = SENSOR_MT9V112;
pr_info("MT9V112 sensor detected\n");
- return 0;
+ return;
}
- return -ENODEV;
+ gspca_dev->usb_err = -ENODEV;
}
-static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m112_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
- for (i = 0; i < ARRAY_SIZE(mt9m112_init); i++) {
- if (i2c_w2(gspca_dev, mt9m112_init[i].reg,
- mt9m112_init[i].val) < 0) {
- pr_err("MT9M112 sensor initialization failed\n");
- return -ENODEV;
- }
- }
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
- | (1 << GAIN_IDX);
+
+ i2c_w2_buf(gspca_dev, mt9m112_init, ARRAY_SIZE(mt9m112_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("MT9M112 sensor initialization failed\n");
+
+ gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
+ | (1 << GAIN);
sd->hstart = 0;
sd->vstart = 2;
- return 0;
}
-static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m111_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
- for (i = 0; i < ARRAY_SIZE(mt9m111_init); i++) {
- if (i2c_w2(gspca_dev, mt9m111_init[i].reg,
- mt9m111_init[i].val) < 0) {
- pr_err("MT9M111 sensor initialization failed\n");
- return -ENODEV;
- }
- }
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
- | (1 << GAIN_IDX);
+
+ i2c_w2_buf(gspca_dev, mt9m111_init, ARRAY_SIZE(mt9m111_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("MT9M111 sensor initialization failed\n");
+
+ gspca_dev->ctrl_dis = (1 << EXPOSURE) | (1 << AUTOGAIN)
+ | (1 << GAIN);
sd->hstart = 0;
sd->vstart = 2;
- return 0;
}
-static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
+static void mt9m001_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
u16 id;
- if (i2c_r2(gspca_dev, 0x00, &id) < 0)
- return -EINVAL;
+ i2c_r2(gspca_dev, 0x00, &id);
+ if (gspca_dev->usb_err < 0)
+ return;
/* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
switch (id) {
@@ -1494,85 +1462,78 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
break;
default:
pr_err("No MT9M001 chip detected, ID = %x\n\n", id);
- return -ENODEV;
+ gspca_dev->usb_err = -ENODEV;
+ return;
}
- for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
- if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
- mt9m001_init[i].val) < 0) {
- pr_err("MT9M001 sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w2_buf(gspca_dev, mt9m001_init, ARRAY_SIZE(mt9m001_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("MT9M001 sensor initialization failed\n");
+
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP) | (1 << VFLIP);
sd->hstart = 1;
sd->vstart = 1;
- return 0;
}
-static int hv7131r_init_sensor(struct gspca_dev *gspca_dev)
+static void hv7131r_init_sensor(struct gspca_dev *gspca_dev)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- for (i = 0; i < ARRAY_SIZE(hv7131r_init); i++) {
- if (i2c_w1(gspca_dev, hv7131r_init[i].reg,
- hv7131r_init[i].val) < 0) {
- pr_err("HV7131R Sensor initialization failed\n");
- return -ENODEV;
- }
- }
+ i2c_w1_buf(gspca_dev, hv7131r_init, ARRAY_SIZE(hv7131r_init));
+ if (gspca_dev->usb_err < 0)
+ pr_err("HV7131R Sensor initialization failed\n");
+
sd->hstart = 0;
sd->vstart = 1;
- return 0;
}
-static int set_cmatrix(struct gspca_dev *gspca_dev)
+static void set_cmatrix(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- s32 hue_coord, hue_index = 180 + sd->hue;
+ int satur;
+ s32 hue_coord, hue_index = 180 + sd->ctrls[HUE].val;
u8 cmatrix[21];
memset(cmatrix, 0, sizeof cmatrix);
- cmatrix[2] = (sd->contrast * 0x25 / 0x100) + 0x26;
+ cmatrix[2] = (sd->ctrls[CONTRAST].val * 0x25 / 0x100) + 0x26;
cmatrix[0] = 0x13 + (cmatrix[2] - 0x26) * 0x13 / 0x25;
cmatrix[4] = 0x07 + (cmatrix[2] - 0x26) * 0x07 / 0x25;
- cmatrix[18] = sd->brightness - 0x80;
+ cmatrix[18] = sd->ctrls[BRIGHTNESS].val - 0x80;
- hue_coord = (hsv_red_x[hue_index] * sd->saturation) >> 8;
+ satur = sd->ctrls[SATURATION].val;
+ hue_coord = (hsv_red_x[hue_index] * satur) >> 8;
cmatrix[6] = hue_coord;
cmatrix[7] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_red_y[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_red_y[hue_index] * satur) >> 8;
cmatrix[8] = hue_coord;
cmatrix[9] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_green_x[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_green_x[hue_index] * satur) >> 8;
cmatrix[10] = hue_coord;
cmatrix[11] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_green_y[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_green_y[hue_index] * satur) >> 8;
cmatrix[12] = hue_coord;
cmatrix[13] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_blue_x[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_blue_x[hue_index] * satur) >> 8;
cmatrix[14] = hue_coord;
cmatrix[15] = (hue_coord >> 8) & 0x0f;
- hue_coord = (hsv_blue_y[hue_index] * sd->saturation) >> 8;
+ hue_coord = (hsv_blue_y[hue_index] * satur) >> 8;
cmatrix[16] = hue_coord;
cmatrix[17] = (hue_coord >> 8) & 0x0f;
- return reg_w(gspca_dev, 0x10e1, cmatrix, 21);
+ reg_w(gspca_dev, 0x10e1, cmatrix, 21);
}
-static int set_gamma(struct gspca_dev *gspca_dev)
+static void set_gamma(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 gamma[17];
- u8 gval = sd->gamma * 0xb8 / 0x100;
-
+ u8 gval = sd->ctrls[GAMMA].val * 0xb8 / 0x100;
gamma[0] = 0x0a;
gamma[1] = 0x13 + (gval * (0xcb - 0x13) / 0xb8);
@@ -1592,29 +1553,29 @@ static int set_gamma(struct gspca_dev *gspca_dev)
gamma[15] = 0xea + (gval * (0xf9 - 0xea) / 0xb8);
gamma[16] = 0xf5;
- return reg_w(gspca_dev, 0x1190, gamma, 17);
+ reg_w(gspca_dev, 0x1190, gamma, 17);
}
-static int set_redblue(struct gspca_dev *gspca_dev)
+static void set_redblue(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- reg_w1(gspca_dev, 0x118c, sd->red);
- reg_w1(gspca_dev, 0x118f, sd->blue);
- return 0;
+
+ reg_w1(gspca_dev, 0x118c, sd->ctrls[RED].val);
+ reg_w1(gspca_dev, 0x118f, sd->ctrls[BLUE].val);
}
-static int set_hvflip(struct gspca_dev *gspca_dev)
+static void set_hvflip(struct gspca_dev *gspca_dev)
{
u8 value, tslb, hflip, vflip;
u16 value2;
struct sd *sd = (struct sd *) gspca_dev;
if ((sd->flags & FLIP_DETECT) && dmi_check_system(flip_dmi_table)) {
- hflip = !sd->hflip;
- vflip = !sd->vflip;
+ hflip = !sd->ctrls[HFLIP].val;
+ vflip = !sd->ctrls[VFLIP].val;
} else {
- hflip = sd->hflip;
- vflip = sd->vflip;
+ hflip = sd->ctrls[HFLIP].val;
+ vflip = sd->ctrls[VFLIP].val;
}
switch (sd->sensor) {
@@ -1625,8 +1586,9 @@ static int set_hvflip(struct gspca_dev *gspca_dev)
if (vflip) {
value |= 0x10;
sd->vstart = 2;
- } else
+ } else {
sd->vstart = 3;
+ }
reg_w1(gspca_dev, 0x1182, sd->vstart);
i2c_w1(gspca_dev, 0x1e, value);
break;
@@ -1674,13 +1636,15 @@ static int set_hvflip(struct gspca_dev *gspca_dev)
i2c_w1(gspca_dev, 0x01, value);
break;
}
- return 0;
}
-static int set_exposure(struct gspca_dev *gspca_dev)
+static void set_exposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 exp[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e};
+ int expo;
+
+ expo = sd->ctrls[EXPOSURE].val;
switch (sd->sensor) {
case SENSOR_OV7660:
case SENSOR_OV7670:
@@ -1688,35 +1652,37 @@ static int set_exposure(struct gspca_dev *gspca_dev)
case SENSOR_OV9650:
exp[0] |= (3 << 4);
exp[2] = 0x2d;
- exp[3] = sd->exposure & 0xff;
- exp[4] = sd->exposure >> 8;
+ exp[3] = expo;
+ exp[4] = expo >> 8;
break;
case SENSOR_MT9M001:
case SENSOR_MT9V112:
case SENSOR_MT9V011:
exp[0] |= (3 << 4);
exp[2] = 0x09;
- exp[3] = sd->exposure >> 8;
- exp[4] = sd->exposure & 0xff;
+ exp[3] = expo >> 8;
+ exp[4] = expo;
break;
case SENSOR_HV7131R:
exp[0] |= (4 << 4);
exp[2] = 0x25;
- exp[3] = (sd->exposure >> 5) & 0xff;
- exp[4] = (sd->exposure << 3) & 0xff;
+ exp[3] = expo >> 5;
+ exp[4] = expo << 3;
exp[5] = 0;
break;
default:
- return 0;
+ return;
}
i2c_w(gspca_dev, exp);
- return 0;
}
-static int set_gain(struct gspca_dev *gspca_dev)
+static void set_gain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 gain[8] = {0x81, sd->i2c_addr, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d};
+ int g;
+
+ g = sd->ctrls[GAIN].val;
switch (sd->sensor) {
case SENSOR_OV7660:
case SENSOR_OV7670:
@@ -1724,238 +1690,50 @@ static int set_gain(struct gspca_dev *gspca_dev)
case SENSOR_OV9655:
case SENSOR_OV9650:
gain[0] |= (2 << 4);
- gain[3] = ov_gain[sd->gain];
+ gain[3] = ov_gain[g];
break;
case SENSOR_MT9V011:
gain[0] |= (3 << 4);
gain[2] = 0x35;
- gain[3] = micron1_gain[sd->gain] >> 8;
- gain[4] = micron1_gain[sd->gain] & 0xff;
+ gain[3] = micron1_gain[g] >> 8;
+ gain[4] = micron1_gain[g];
break;
case SENSOR_MT9V112:
gain[0] |= (3 << 4);
gain[2] = 0x2f;
- gain[3] = micron1_gain[sd->gain] >> 8;
- gain[4] = micron1_gain[sd->gain] & 0xff;
+ gain[3] = micron1_gain[g] >> 8;
+ gain[4] = micron1_gain[g];
break;
case SENSOR_MT9M001:
gain[0] |= (3 << 4);
gain[2] = 0x2f;
- gain[3] = micron2_gain[sd->gain] >> 8;
- gain[4] = micron2_gain[sd->gain] & 0xff;
+ gain[3] = micron2_gain[g] >> 8;
+ gain[4] = micron2_gain[g];
break;
case SENSOR_HV7131R:
gain[0] |= (2 << 4);
gain[2] = 0x30;
- gain[3] = hv7131r_gain[sd->gain];
+ gain[3] = hv7131r_gain[g];
break;
default:
- return 0;
+ return;
}
i2c_w(gspca_dev, gain);
- return 0;
-}
-
-static int sd_setbrightness(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->brightness = val;
- if (gspca_dev->streaming)
- return set_cmatrix(gspca_dev);
- return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->brightness;
- return 0;
-}
-
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->contrast = val;
- if (gspca_dev->streaming)
- return set_cmatrix(gspca_dev);
- return 0;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->contrast;
- return 0;
-}
-
-static int sd_setsaturation(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->saturation = val;
- if (gspca_dev->streaming)
- return set_cmatrix(gspca_dev);
- return 0;
-}
-
-static int sd_getsaturation(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->saturation;
- return 0;
-}
-
-static int sd_sethue(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->hue = val;
- if (gspca_dev->streaming)
- return set_cmatrix(gspca_dev);
- return 0;
-}
-
-static int sd_gethue(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->hue;
- return 0;
-}
-
-static int sd_setgamma(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gamma = val;
- if (gspca_dev->streaming)
- return set_gamma(gspca_dev);
- return 0;
-}
-
-static int sd_getgamma(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->gamma;
- return 0;
-}
-
-static int sd_setredbalance(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->red = val;
- if (gspca_dev->streaming)
- return set_redblue(gspca_dev);
- return 0;
-}
-
-static int sd_getredbalance(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->red;
- return 0;
}
-static int sd_setbluebalance(struct gspca_dev *gspca_dev, s32 val)
+static void set_quality(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->blue = val;
- if (gspca_dev->streaming)
- return set_redblue(gspca_dev);
- return 0;
-}
-
-static int sd_getbluebalance(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->blue;
- return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->hflip = val;
- if (gspca_dev->streaming)
- return set_hvflip(gspca_dev);
- return 0;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->hflip;
- return 0;
-}
-
-static int sd_setvflip(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->vflip = val;
- if (gspca_dev->streaming)
- return set_hvflip(gspca_dev);
- return 0;
-}
-
-static int sd_getvflip(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->vflip;
- return 0;
-}
-
-static int sd_setexposure(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->exposure = val;
- if (gspca_dev->streaming)
- return set_exposure(gspca_dev);
- return 0;
-}
-
-static int sd_getexposure(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->exposure;
- return 0;
-}
-
-static int sd_setgain(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gain = val;
- if (gspca_dev->streaming)
- return set_gain(gspca_dev);
- return 0;
-}
-
-static int sd_getgain(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->gain;
- return 0;
-}
-
-static int sd_setautoexposure(struct gspca_dev *gspca_dev, s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- sd->auto_exposure = val;
- return 0;
-}
-
-static int sd_getautoexposure(struct gspca_dev *gspca_dev, s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->auto_exposure;
- return 0;
+ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+ reg_w1(gspca_dev, 0x1061, 0x01); /* stop transfer */
+ reg_w1(gspca_dev, 0x10e0, sd->fmt | 0x20); /* write QTAB */
+ reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
+ reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
+ reg_w1(gspca_dev, 0x1061, 0x03); /* restart transfer */
+ reg_w1(gspca_dev, 0x10e0, sd->fmt);
+ sd->fmt ^= 0x0c; /* invert QTAB use + write */
+ reg_w1(gspca_dev, 0x10e0, sd->fmt);
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1963,28 +1741,26 @@ static int sd_dbg_g_register(struct gspca_dev *gspca_dev,
struct v4l2_dbg_register *reg)
{
struct sd *sd = (struct sd *) gspca_dev;
+
switch (reg->match.type) {
case V4L2_CHIP_MATCH_HOST:
if (reg->match.addr != 0)
return -EINVAL;
if (reg->reg < 0x1000 || reg->reg > 0x11ff)
return -EINVAL;
- if (reg_r(gspca_dev, reg->reg, 1) < 0)
- return -EINVAL;
+ reg_r(gspca_dev, reg->reg, 1);
reg->val = gspca_dev->usb_buf[0];
- return 0;
+ return gspca_dev->usb_err;
case V4L2_CHIP_MATCH_I2C_ADDR:
if (reg->match.addr != sd->i2c_addr)
return -EINVAL;
if (sd->sensor >= SENSOR_MT9V011 &&
sd->sensor <= SENSOR_MT9M112) {
- if (i2c_r2(gspca_dev, reg->reg, (u16 *)&reg->val) < 0)
- return -EINVAL;
+ i2c_r2(gspca_dev, reg->reg, (u16 *) &reg->val);
} else {
- if (i2c_r1(gspca_dev, reg->reg, (u8 *)&reg->val) < 0)
- return -EINVAL;
+ i2c_r1(gspca_dev, reg->reg, (u8 *) &reg->val);
}
- return 0;
+ return gspca_dev->usb_err;
}
return -EINVAL;
}
@@ -1993,27 +1769,25 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
struct v4l2_dbg_register *reg)
{
struct sd *sd = (struct sd *) gspca_dev;
+
switch (reg->match.type) {
case V4L2_CHIP_MATCH_HOST:
if (reg->match.addr != 0)
return -EINVAL;
if (reg->reg < 0x1000 || reg->reg > 0x11ff)
return -EINVAL;
- if (reg_w1(gspca_dev, reg->reg, reg->val) < 0)
- return -EINVAL;
- return 0;
+ reg_w1(gspca_dev, reg->reg, reg->val);
+ return gspca_dev->usb_err;
case V4L2_CHIP_MATCH_I2C_ADDR:
if (reg->match.addr != sd->i2c_addr)
return -EINVAL;
if (sd->sensor >= SENSOR_MT9V011 &&
sd->sensor <= SENSOR_MT9M112) {
- if (i2c_w2(gspca_dev, reg->reg, reg->val) < 0)
- return -EINVAL;
+ i2c_w2(gspca_dev, reg->reg, reg->val);
} else {
- if (i2c_w1(gspca_dev, reg->reg, reg->val) < 0)
- return -EINVAL;
+ i2c_w1(gspca_dev, reg->reg, reg->val);
}
- return 0;
+ return gspca_dev->usb_err;
}
return -EINVAL;
}
@@ -2048,10 +1822,11 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct cam *cam;
cam = &gspca_dev->cam;
+ cam->needs_full_bandwidth = 1;
- sd->sensor = (id->driver_info >> 8) & 0xff;
- sd->i2c_addr = id->driver_info & 0xff;
- sd->flags = (id->driver_info >> 16) & 0xff;
+ sd->sensor = id->driver_info >> 8;
+ sd->i2c_addr = id->driver_info;
+ sd->flags = id->driver_info >> 16;
switch (sd->sensor) {
case SENSOR_MT9M112:
@@ -2075,21 +1850,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->older_step = 0;
sd->exposure_step = 16;
- sd->brightness = BRIGHTNESS_DEFAULT;
- sd->contrast = CONTRAST_DEFAULT;
- sd->saturation = SATURATION_DEFAULT;
- sd->hue = HUE_DEFAULT;
- sd->gamma = GAMMA_DEFAULT;
- sd->red = RED_DEFAULT;
- sd->blue = BLUE_DEFAULT;
+ gspca_dev->cam.ctrls = sd->ctrls;
- sd->hflip = HFLIP_DEFAULT;
- sd->vflip = VFLIP_DEFAULT;
- sd->exposure = EXPOSURE_DEFAULT;
- sd->gain = GAIN_DEFAULT;
- sd->auto_exposure = AUTO_EXPOSURE_DEFAULT;
-
- sd->quality = 95;
+ INIT_WORK(&sd->work, qual_upd);
return 0;
}
@@ -2104,9 +1867,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
for (i = 0; i < ARRAY_SIZE(bridge_init); i++) {
value = bridge_init[i][1];
- if (reg_w(gspca_dev, bridge_init[i][0], &value, 1) < 0) {
+ reg_w(gspca_dev, bridge_init[i][0], &value, 1);
+ if (gspca_dev->usb_err < 0) {
pr_err("Device initialization failed\n");
- return -ENODEV;
+ return gspca_dev->usb_err;
}
}
@@ -2115,72 +1879,85 @@ static int sd_init(struct gspca_dev *gspca_dev)
else
reg_w1(gspca_dev, 0x1006, 0x20);
- if (reg_w(gspca_dev, 0x10c0, i2c_init, 9) < 0) {
+ reg_w(gspca_dev, 0x10c0, i2c_init, 9);
+ if (gspca_dev->usb_err < 0) {
pr_err("Device initialization failed\n");
- return -ENODEV;
+ return gspca_dev->usb_err;
}
switch (sd->sensor) {
case SENSOR_OV9650:
- if (ov9650_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov9650_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV9650 sensor detected\n");
break;
case SENSOR_OV9655:
- if (ov9655_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov9655_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV9655 sensor detected\n");
break;
case SENSOR_SOI968:
- if (soi968_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ soi968_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("SOI968 sensor detected\n");
break;
case SENSOR_OV7660:
- if (ov7660_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov7660_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV7660 sensor detected\n");
break;
case SENSOR_OV7670:
- if (ov7670_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ ov7670_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("OV7670 sensor detected\n");
break;
case SENSOR_MT9VPRB:
- if (mt9v_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9v_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
+ pr_info("MT9VPRB sensor detected\n");
break;
case SENSOR_MT9M111:
- if (mt9m111_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9m111_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("MT9M111 sensor detected\n");
break;
case SENSOR_MT9M112:
- if (mt9m112_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9m112_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("MT9M112 sensor detected\n");
break;
case SENSOR_MT9M001:
- if (mt9m001_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ mt9m001_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
break;
case SENSOR_HV7131R:
- if (hv7131r_init_sensor(gspca_dev) < 0)
- return -ENODEV;
+ hv7131r_init_sensor(gspca_dev);
+ if (gspca_dev->usb_err < 0)
+ break;
pr_info("HV7131R sensor detected\n");
break;
default:
- pr_info("Unsupported Sensor\n");
- return -ENODEV;
+ pr_err("Unsupported sensor\n");
+ gspca_dev->usb_err = -ENODEV;
}
- return 0;
+ return gspca_dev->usb_err;
}
static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
{
struct sd *sd = (struct sd *) gspca_dev;
u8 value;
+
switch (sd->sensor) {
case SENSOR_SOI968:
if (mode & MODE_SXGA) {
@@ -2233,6 +2010,43 @@ static void configure_sensor_output(struct gspca_dev *gspca_dev, int mode)
}
}
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ struct usb_interface *intf;
+ u32 flags = gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv;
+
+ /*
+ * When using the SN9C20X_I420 fmt the sn9c20x needs more bandwidth
+ * than our regular bandwidth calculations reserve, so we force the
+ * use of a specific altsetting when using the SN9C20X_I420 fmt.
+ */
+ if (!(flags & (MODE_RAW | MODE_JPEG))) {
+ intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+
+ if (intf->num_altsetting != 9) {
+ pr_warn("sn9c20x camera with unknown number of alt "
+ "settings (%d), please report!\n",
+ intf->num_altsetting);
+ gspca_dev->alt = intf->num_altsetting;
+ return 0;
+ }
+
+ switch (gspca_dev->width) {
+ case 160: /* 160x120 */
+ gspca_dev->alt = 2;
+ break;
+ case 320: /* 320x240 */
+ gspca_dev->alt = 6;
+ break;
+ default: /* >= 640x480 */
+ gspca_dev->alt = 9;
+ break;
+ }
+ }
+
+ return 0;
+}
+
#define HW_WIN(mode, hstart, vstart) \
((const u8 []){hstart, 0, vstart, 0, \
(mode & MODE_SXGA ? 1280 >> 4 : 640 >> 4), \
@@ -2253,14 +2067,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
jpeg_define(sd->jpeg_hdr, height, width,
0x21);
- jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
if (mode & MODE_RAW)
fmt = 0x2d;
else if (mode & MODE_JPEG)
- fmt = 0x2c;
+ fmt = 0x24;
else
fmt = 0x2f; /* YUV 420 */
+ sd->fmt = fmt;
switch (mode & SCALE_MASK) {
case SCALE_1280x1024:
@@ -2297,18 +2112,37 @@ static int sd_start(struct gspca_dev *gspca_dev)
set_hvflip(gspca_dev);
reg_w1(gspca_dev, 0x1007, 0x20);
+ reg_w1(gspca_dev, 0x1061, 0x03);
+
+ /* if JPEG, prepare the compression quality update */
+ if (mode & MODE_JPEG) {
+ sd->pktsz = sd->npkt = 0;
+ sd->nchg = 0;
+ sd->work_thread =
+ create_singlethread_workqueue(KBUILD_MODNAME);
+ }
- reg_r(gspca_dev, 0x1061, 1);
- reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] | 0x02);
- return 0;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
reg_w1(gspca_dev, 0x1007, 0x00);
+ reg_w1(gspca_dev, 0x1061, 0x01);
+}
+
+/* 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 *sd = (struct sd *) gspca_dev;
- reg_r(gspca_dev, 0x1061, 1);
- reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
+ if (sd->work_thread != NULL) {
+ mutex_unlock(&gspca_dev->usb_lock);
+ destroy_workqueue(sd->work_thread);
+ mutex_lock(&gspca_dev->usb_lock);
+ sd->work_thread = NULL;
+ }
}
static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
@@ -2322,15 +2156,15 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
* and exposure steps
*/
if (avg_lum < MIN_AVG_LUM) {
- if (sd->exposure > 0x1770)
+ if (sd->ctrls[EXPOSURE].val > 0x1770)
return;
- new_exp = sd->exposure + sd->exposure_step;
+ new_exp = sd->ctrls[EXPOSURE].val + sd->exposure_step;
if (new_exp > 0x1770)
new_exp = 0x1770;
if (new_exp < 0x10)
new_exp = 0x10;
- sd->exposure = new_exp;
+ sd->ctrls[EXPOSURE].val = new_exp;
set_exposure(gspca_dev);
sd->older_step = sd->old_step;
@@ -2342,14 +2176,14 @@ static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
sd->exposure_step += 2;
}
if (avg_lum > MAX_AVG_LUM) {
- if (sd->exposure < 0x10)
+ if (sd->ctrls[EXPOSURE].val < 0x10)
return;
- new_exp = sd->exposure - sd->exposure_step;
+ new_exp = sd->ctrls[EXPOSURE].val - sd->exposure_step;
if (new_exp > 0x1700)
new_exp = 0x1770;
if (new_exp < 0x10)
new_exp = 0x10;
- sd->exposure = new_exp;
+ sd->ctrls[EXPOSURE].val = new_exp;
set_exposure(gspca_dev);
sd->older_step = sd->old_step;
sd->old_step = 0;
@@ -2366,14 +2200,14 @@ static void do_autogain(struct gspca_dev *gspca_dev, u16 avg_lum)
struct sd *sd = (struct sd *) gspca_dev;
if (avg_lum < MIN_AVG_LUM) {
- if (sd->gain + 1 <= 28) {
- sd->gain++;
+ if (sd->ctrls[GAIN].val + 1 <= 28) {
+ sd->ctrls[GAIN].val++;
set_gain(gspca_dev);
}
}
if (avg_lum > MAX_AVG_LUM) {
- if (sd->gain > 0) {
- sd->gain--;
+ if (sd->ctrls[GAIN].val > 0) {
+ sd->ctrls[GAIN].val--;
set_gain(gspca_dev);
}
}
@@ -2384,7 +2218,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int avg_lum;
- if (!sd->auto_exposure)
+ if (!sd->ctrls[AUTOGAIN].val)
return;
avg_lum = atomic_read(&sd->avg_lum);
@@ -2394,33 +2228,92 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
do_autoexposure(gspca_dev, avg_lum);
}
+/* JPEG quality update */
+/* This function is executed from a work queue. */
+static void qual_upd(struct work_struct *work)
+{
+ struct sd *sd = container_of(work, struct sd, work);
+ struct gspca_dev *gspca_dev = &sd->gspca_dev;
+
+ mutex_lock(&gspca_dev->usb_lock);
+ PDEBUG(D_STREAM, "qual_upd %d%%", sd->ctrls[QUALITY].val);
+ set_quality(gspca_dev);
+ mutex_unlock(&gspca_dev->usb_lock);
+}
+
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet */
int len) /* interrupt packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret = -EINVAL;
+
if (!(sd->flags & HAS_NO_BUTTON) && len == 1) {
- input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
- input_sync(gspca_dev->input_dev);
- input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
- input_sync(gspca_dev->input_dev);
- ret = 0;
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
+ input_sync(gspca_dev->input_dev);
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ return 0;
}
- return ret;
+ return -EINVAL;
}
#endif
+/* check the JPEG compression */
+static void transfer_check(struct gspca_dev *gspca_dev,
+ u8 *data)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int new_qual, r;
+
+ new_qual = 0;
+
+ /* if USB error, discard the frame and decrease the quality */
+ if (data[6] & 0x08) { /* USB FIFO full */
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ new_qual = -5;
+ } else {
+
+ /* else, compute the filling rate and a new JPEG quality */
+ r = (sd->pktsz * 100) /
+ (sd->npkt *
+ gspca_dev->urb[0]->iso_frame_desc[0].length);
+ if (r >= 85)
+ new_qual = -3;
+ else if (r < 75)
+ new_qual = 2;
+ }
+ if (new_qual != 0) {
+ sd->nchg += new_qual;
+ if (sd->nchg < -6 || sd->nchg >= 12) {
+ sd->nchg = 0;
+ new_qual += sd->ctrls[QUALITY].val;
+ if (new_qual < QUALITY_MIN)
+ new_qual = QUALITY_MIN;
+ else if (new_qual > QUALITY_MAX)
+ new_qual = QUALITY_MAX;
+ if (new_qual != sd->ctrls[QUALITY].val) {
+ sd->ctrls[QUALITY].val = new_qual;
+ queue_work(sd->work_thread, &sd->work);
+ }
+ }
+ } else {
+ sd->nchg = 0;
+ }
+ sd->pktsz = sd->npkt = 0;
+}
+
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;
- int avg_lum;
+ int avg_lum, is_jpeg;
static u8 frame_header[] =
{0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
- if (len == 64 && memcmp(data, frame_header, 6) == 0) {
+
+ is_jpeg = (sd->fmt & 0x03) == 0;
+ if (len >= 64 && memcmp(data, frame_header, 6) == 0) {
avg_lum = ((data[35] >> 2) & 3) |
(data[20] << 2) |
(data[19] << 10);
@@ -2447,12 +2340,18 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
(data[33] << 10);
avg_lum >>= 9;
atomic_set(&sd->avg_lum, avg_lum);
+
+ if (is_jpeg)
+ transfer_check(gspca_dev, data);
+
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
- return;
+ len -= 64;
+ if (len == 0)
+ return;
+ data += 64;
}
if (gspca_dev->last_packet_type == LAST_PACKET) {
- if (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv
- & MODE_JPEG) {
+ if (is_jpeg) {
gspca_frame_add(gspca_dev, FIRST_PACKET,
sd->jpeg_hdr, JPEG_HDR_SZ);
gspca_frame_add(gspca_dev, INTER_PACKET,
@@ -2462,19 +2361,26 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data, len);
}
} else {
+ /* if JPEG, count the packets and their size */
+ if (is_jpeg) {
+ sd->npkt++;
+ sd->pktsz += len;
+ }
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
}
/* sub-driver description */
static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
.init = sd_init,
+ .isoc_init = sd_isoc_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
@@ -2543,7 +2449,7 @@ static int sd_probe(struct usb_interface *intf,
}
static struct usb_driver sd_driver = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index ddb392dc4f2..6a1148d7fe9 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -1079,20 +1079,23 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
cam->npkt = 36; /* 36 packets per ISOC message */
- if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) {
- sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN;
- sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX;
- sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF;
- }
-
return 0;
}
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
const __u8 stop = 0x09; /* Disable stream turn of LED */
+ if (sensor_data[sd->sensor].flags & F_COARSE_EXPO) {
+ sd->ctrls[EXPOSURE].min = COARSE_EXPOSURE_MIN;
+ sd->ctrls[EXPOSURE].max = COARSE_EXPOSURE_MAX;
+ sd->ctrls[EXPOSURE].def = COARSE_EXPOSURE_DEF;
+ if (sd->ctrls[EXPOSURE].val > COARSE_EXPOSURE_MAX)
+ sd->ctrls[EXPOSURE].val = COARSE_EXPOSURE_DEF;
+ }
+
reg_w(gspca_dev, 0x01, &stop, 1);
return 0;
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index afa3186b803..db8e5084df0 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -39,7 +39,9 @@ enum e_ctrl {
BLUE,
RED,
GAMMA,
+ EXPOSURE,
AUTOGAIN,
+ GAIN,
HFLIP,
VFLIP,
SHARPNESS,
@@ -131,7 +133,9 @@ static void setcontrast(struct gspca_dev *gspca_dev);
static void setcolors(struct gspca_dev *gspca_dev);
static void setredblue(struct gspca_dev *gspca_dev);
static void setgamma(struct gspca_dev *gspca_dev);
-static void setautogain(struct gspca_dev *gspca_dev);
+static void setexposure(struct gspca_dev *gspca_dev);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static void setgain(struct gspca_dev *gspca_dev);
static void sethvflip(struct gspca_dev *gspca_dev);
static void setsharpness(struct gspca_dev *gspca_dev);
static void setillum(struct gspca_dev *gspca_dev);
@@ -213,6 +217,18 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
},
.set_control = setgamma
},
+[EXPOSURE] = {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 500,
+ .maximum = 1500,
+ .step = 1,
+ .default_value = 1024
+ },
+ .set_control = setexposure
+ },
[AUTOGAIN] = {
{
.id = V4L2_CID_AUTOGAIN,
@@ -223,7 +239,19 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
.step = 1,
.default_value = 1
},
- .set_control = setautogain
+ .set = sd_setautogain,
+ },
+[GAIN] = {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 4,
+ .maximum = 49,
+ .step = 1,
+ .default_value = 15
+ },
+ .set_control = setgain
},
[HFLIP] = {
{
@@ -290,60 +318,87 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
/* table of the disabled controls */
static const __u32 ctrl_dis[] = {
-[SENSOR_ADCM1700] = (1 << AUTOGAIN) |
+[SENSOR_ADCM1700] = (1 << EXPOSURE) |
+ (1 << AUTOGAIN) |
+ (1 << GAIN) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_GC0307] = (1 << HFLIP) |
+[SENSOR_GC0307] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_HV7131R] = (1 << HFLIP) |
+[SENSOR_HV7131R] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << FREQ),
-[SENSOR_MI0360] = (1 << HFLIP) |
+[SENSOR_MI0360] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_MI0360B] = (1 << HFLIP) |
+[SENSOR_MI0360B] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_MO4000] = (1 << HFLIP) |
+[SENSOR_MO4000] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_MT9V111] = (1 << HFLIP) |
+[SENSOR_MT9V111] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_OM6802] = (1 << HFLIP) |
+[SENSOR_OM6802] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_OV7630] = (1 << HFLIP),
+[SENSOR_OV7630] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP),
-[SENSOR_OV7648] = (1 << HFLIP),
+[SENSOR_OV7648] = (1 << EXPOSURE) |
+ (1 << GAIN) |
+ (1 << HFLIP),
-[SENSOR_OV7660] = (1 << AUTOGAIN) |
+[SENSOR_OV7660] = (1 << EXPOSURE) |
+ (1 << AUTOGAIN) |
+ (1 << GAIN) |
(1 << HFLIP) |
(1 << VFLIP),
-[SENSOR_PO1030] = (1 << AUTOGAIN) |
+[SENSOR_PO1030] = (1 << EXPOSURE) |
+ (1 << AUTOGAIN) |
+ (1 << GAIN) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_PO2030N] = (1 << AUTOGAIN) |
- (1 << FREQ),
+[SENSOR_PO2030N] = (1 << FREQ),
-[SENSOR_SOI768] = (1 << AUTOGAIN) |
+[SENSOR_SOI768] = (1 << EXPOSURE) |
+ (1 << AUTOGAIN) |
+ (1 << GAIN) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
-[SENSOR_SP80708] = (1 << AUTOGAIN) |
+[SENSOR_SP80708] = (1 << EXPOSURE) |
+ (1 << AUTOGAIN) |
+ (1 << GAIN) |
(1 << HFLIP) |
(1 << VFLIP) |
(1 << FREQ),
@@ -1235,21 +1290,13 @@ static const u8 po2030n_sensor_param1[][8] = {
{DELAY, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */
{0xa1, 0x6e, 0x1b, 0xf4, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10},
- {0xd1, 0x6e, 0x16, 0x50, 0x40, 0x49, 0x40, 0x10},
+ {0xd1, 0x6e, 0x16, 0x40, 0x40, 0x40, 0x40, 0x10}, /* RGBG gains */
/*param2*/
{0xa1, 0x6e, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x05, 0x6f, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x07, 0x25, 0x00, 0x00, 0x00, 0x10},
- {0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10},
- {0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10},
-/*after start*/
- {0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10},
- {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
- {0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10},
- {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
- {0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10},
{}
};
@@ -1779,10 +1826,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->ag_cnt = -1;
sd->quality = QUALITY_DEF;
- /* if USB 1.1, let some bandwidth for the audio device */
- if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH)
- gspca_dev->nbalt--;
-
INIT_WORK(&sd->work, qual_upd);
return 0;
@@ -1862,7 +1905,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
return gspca_dev->usb_err;
}
-static u32 setexposure(struct gspca_dev *gspca_dev,
+static u32 expo_adjust(struct gspca_dev *gspca_dev,
u32 expo)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1986,28 +2029,28 @@ static void setbrightness(struct gspca_dev *gspca_dev)
expo = 0x002dc6c0;
else if (expo < 0x02a0)
expo = 0x02a0;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
break;
case SENSOR_MI0360:
case SENSOR_MO4000:
expo = brightness << 4;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
break;
case SENSOR_MI0360B:
expo = brightness << 2;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
break;
case SENSOR_GC0307:
expo = brightness;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
return; /* don't set the Y offset */
case SENSOR_MT9V111:
expo = brightness << 2;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
return; /* don't set the Y offset */
case SENSOR_OM6802:
expo = brightness << 2;
- sd->exposure = setexposure(gspca_dev, expo);
+ sd->exposure = expo_adjust(gspca_dev, expo);
return; /* Y offset already set */
}
@@ -2063,6 +2106,16 @@ static void setredblue(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (sd->sensor == SENSOR_PO2030N) {
+ u8 rg1b[] = /* red green1 blue (no g2) */
+ {0xc1, 0x6e, 0x16, 0x00, 0x40, 0x00, 0x00, 0x10};
+
+ /* 0x40 = normal value = gain x 1 */
+ rg1b[3] = sd->ctrls[RED].val * 2;
+ rg1b[5] = sd->ctrls[BLUE].val * 2;
+ i2c_w8(gspca_dev, rg1b);
+ return;
+ }
reg_w1(gspca_dev, 0x05, sd->ctrls[RED].val);
/* reg_w1(gspca_dev, 0x07, 32); */
reg_w1(gspca_dev, 0x06, sd->ctrls[BLUE].val);
@@ -2106,6 +2159,23 @@ static void setgamma(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x20, gamma, sizeof gamma);
}
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PO2030N) {
+ u8 rexpo[] = /* 1a: expo H, 1b: expo M */
+ {0xa1, 0x6e, 0x1a, 0x00, 0x40, 0x00, 0x00, 0x10};
+
+ rexpo[3] = sd->ctrls[EXPOSURE].val >> 8;
+ i2c_w8(gspca_dev, rexpo);
+ msleep(6);
+ rexpo[2] = 0x1b;
+ rexpo[3] = sd->ctrls[EXPOSURE].val;
+ i2c_w8(gspca_dev, rexpo);
+ }
+}
+
static void setautogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2133,6 +2203,19 @@ static void setautogain(struct gspca_dev *gspca_dev)
sd->ag_cnt = -1;
}
+static void setgain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_PO2030N) {
+ u8 rgain[] = /* 15: gain */
+ {0xa1, 0x6e, 0x15, 0x00, 0x40, 0x00, 0x00, 0x15};
+
+ rgain[3] = sd->ctrls[GAIN].val;
+ i2c_w8(gspca_dev, rgain);
+ }
+}
+
static void sethvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2397,7 +2480,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x17, reg17);
reg01 &= ~S_PWR_DN; /* sensor power on */
reg_w1(gspca_dev, 0x01, reg01);
- reg01 &= ~SYS_SEL_48M;
+ reg01 &= ~SCL_SEL_OD; /* remove open-drain mode */
reg_w1(gspca_dev, 0x01, reg01);
switch (sd->sensor) {
@@ -2617,6 +2700,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
setcontrast(gspca_dev);
setcolors(gspca_dev);
setautogain(gspca_dev);
+ if (!(gspca_dev->ctrl_inac & ((1 << EXPOSURE) | (1 << GAIN)))) {
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+ }
setfreq(gspca_dev);
sd->pktsz = sd->npkt = 0;
@@ -2713,6 +2800,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
}
}
+/* !! coarse_grained_expo_autogain is not used !! */
+#define exp_too_low_cnt bridge
+#define exp_too_high_cnt sensor
+
+#include "autogain_functions.h"
+
static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2730,6 +2823,13 @@ static void do_autogain(struct gspca_dev *gspca_dev)
delta = atomic_read(&sd->avg_lum);
PDEBUG(D_FRAM, "mean lum %d", delta);
+
+ if (sd->sensor == SENSOR_PO2030N) {
+ auto_gain_n_exposure(gspca_dev, delta, luma_mean, luma_delta,
+ 15, 1024);
+ return;
+ }
+
if (delta < luma_mean - luma_delta ||
delta > luma_mean + luma_delta) {
switch (sd->sensor) {
@@ -2738,7 +2838,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
expotimes += (luma_mean - delta) >> 6;
if (expotimes < 0)
expotimes = 0;
- sd->exposure = setexposure(gspca_dev,
+ sd->exposure = expo_adjust(gspca_dev,
(unsigned int) expotimes);
break;
case SENSOR_HV7131R:
@@ -2746,7 +2846,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
expotimes += (luma_mean - delta) >> 4;
if (expotimes < 0)
expotimes = 0;
- sd->exposure = setexposure(gspca_dev,
+ sd->exposure = expo_adjust(gspca_dev,
(unsigned int) (expotimes << 8));
break;
case SENSOR_OM6802:
@@ -2755,7 +2855,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
expotimes += (luma_mean - delta) >> 2;
if (expotimes < 0)
expotimes = 0;
- sd->exposure = setexposure(gspca_dev,
+ sd->exposure = expo_adjust(gspca_dev,
(unsigned int) expotimes);
setredblue(gspca_dev);
break;
@@ -2767,7 +2867,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
expotimes += (luma_mean - delta) >> 6;
if (expotimes < 0)
expotimes = 0;
- sd->exposure = setexposure(gspca_dev,
+ sd->exposure = expo_adjust(gspca_dev,
(unsigned int) expotimes);
setredblue(gspca_dev);
break;
@@ -2942,16 +3042,18 @@ marker_found:
}
}
-static int sd_get_jcomp(struct gspca_dev *gspca_dev,
- struct v4l2_jpegcompression *jcomp)
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
{
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;
+ sd->ctrls[AUTOGAIN].val = val;
+ if (val)
+ gspca_dev->ctrl_inac |= (1 << EXPOSURE) | (1 << GAIN);
+ else
+ gspca_dev->ctrl_inac &= ~(1 << EXPOSURE) & ~(1 << GAIN);
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
+ return gspca_dev->usb_err;
}
static int sd_querymenu(struct gspca_dev *gspca_dev,
@@ -3006,7 +3108,6 @@ static const struct sd_desc sd_desc = {
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
- .get_jcomp = sd_get_jcomp,
.querymenu = sd_querymenu,
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index 259a0c73c66..4a5f209ce71 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -451,7 +451,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
cam = &gspca_dev->cam;
- gspca_dev->nbalt = 7 + 1; /* choose alternate 7 first */
+ cam->needs_full_bandwidth = 1;
sd->chip_revision = id->driver_info;
if (sd->chip_revision == Rev012A) {
diff --git a/drivers/media/video/gspca/stv06xx/Makefile b/drivers/media/video/gspca/stv06xx/Makefile
index 5b318faf9aa..38bc41061d8 100644
--- a/drivers/media/video/gspca/stv06xx/Makefile
+++ b/drivers/media/video/gspca/stv06xx/Makefile
@@ -6,5 +6,5 @@ gspca_stv06xx-objs := stv06xx.o \
stv06xx_pb0100.o \
stv06xx_st6422.o
-ccflags-y += -Idrivers/media/video/gspca
+ccflags-y += -I$(srctree)/drivers/media/video/gspca
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index 0ab425fbea9..91d99b4cc57 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -36,8 +36,8 @@ MODULE_AUTHOR("Erik Andrén");
MODULE_DESCRIPTION("STV06XX USB Camera Driver");
MODULE_LICENSE("GPL");
-static int dump_bridge;
-static int dump_sensor;
+static bool dump_bridge;
+static bool dump_sensor;
int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data)
{
@@ -304,7 +304,7 @@ static int stv06xx_isoc_init(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
/* Start isoc bandwidth "negotiation" at max isoc bandwidth */
- alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
alt->endpoint[0].desc.wMaxPacketSize =
cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]);
@@ -317,7 +317,7 @@ static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev)
struct usb_host_interface *alt;
struct sd *sd = (struct sd *) gspca_dev;
- alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode];
if (packet_size <= min_packet_size)
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index ea44deb66af..9b9f85a8e60 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -30,6 +30,7 @@
#define MODULE_NAME "t613"
+#include <linux/input.h>
#include <linux/slab.h>
#include "gspca.h"
@@ -57,6 +58,7 @@ struct sd {
u8 effect;
u8 sensor;
+ u8 button_pressed;
};
enum sensors {
SENSOR_OM6802,
@@ -1095,15 +1097,35 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
msleep(20);
reg_w(gspca_dev, 0x0309);
}
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ /* If the last button state is pressed, release it now! */
+ if (sd->button_pressed) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ sd->button_pressed = 0;
+ }
+#endif
}
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;
int pkt_type;
if (data[0] == 0x5a) {
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ if (len > 20) {
+ u8 state = (data[20] & 0x80) ? 1 : 0;
+ if (sd->button_pressed != state) {
+ input_report_key(gspca_dev->input_dev,
+ KEY_CAMERA, state);
+ input_sync(gspca_dev->input_dev);
+ sd->button_pressed = state;
+ }
+ }
+#endif
/* Control Packet, after this came the header again,
* but extra bytes came in the packet before this,
* sometimes an EOF arrives, sometimes not... */
@@ -1410,6 +1432,9 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ .other_input = 1,
+#endif
};
/* -- module initialisation -- */
diff --git a/drivers/media/video/gspca/topro.c b/drivers/media/video/gspca/topro.c
index b2695b1dc60..444d3c5b907 100644
--- a/drivers/media/video/gspca/topro.c
+++ b/drivers/media/video/gspca/topro.c
@@ -3946,7 +3946,7 @@ static int get_fr_idx(struct gspca_dev *gspca_dev)
/* 640x480 * 30 fps does not work */
if (i == 6 /* if 30 fps */
&& gspca_dev->width == 640)
- i = 0x86; /* 15 fps */
+ i = 0x05; /* 15 fps */
} else {
for (i = 0; i < ARRAY_SIZE(rates_6810) - 1; i++) {
if (sd->framerate >= rates_6810[i])
diff --git a/drivers/media/video/gspca/vicam.c b/drivers/media/video/gspca/vicam.c
index d12ea1518ac..911152e169d 100644
--- a/drivers/media/video/gspca/vicam.c
+++ b/drivers/media/video/gspca/vicam.c
@@ -324,7 +324,8 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
dev->work_thread = NULL;
mutex_lock(&gspca_dev->usb_lock);
- vicam_set_camera_power(gspca_dev, 0);
+ if (gspca_dev->present)
+ vicam_set_camera_power(gspca_dev, 0);
}
/* Table of supported USB devices */
diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c
index fbb6ed25ec3..ecada178bce 100644
--- a/drivers/media/video/gspca/xirlink_cit.c
+++ b/drivers/media/video/gspca/xirlink_cit.c
@@ -995,14 +995,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
case CIT_MODEL0:
cam->cam_mode = model0_mode;
cam->nmodes = ARRAY_SIZE(model0_mode);
- cam->reverse_alts = 1;
gspca_dev->ctrl_dis = ~((1 << SD_CONTRAST) | (1 << SD_HFLIP));
sd->sof_len = 4;
break;
case CIT_MODEL1:
cam->cam_mode = cif_yuv_mode;
cam->nmodes = ARRAY_SIZE(cif_yuv_mode);
- cam->reverse_alts = 1;
gspca_dev->ctrl_dis = (1 << SD_HUE) | (1 << SD_HFLIP);
sd->sof_len = 4;
break;
@@ -2791,7 +2789,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev)
}
/* Start isoc bandwidth "negotiation" at max isoc bandwidth */
- alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size);
return 0;
@@ -2814,7 +2812,7 @@ static int sd_isoc_nego(struct gspca_dev *gspca_dev)
break;
}
- alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
if (packet_size <= min_packet_size)
return -EIO;
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index 0202fead6b9..7d9a4f1be9d 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -1,7 +1,7 @@
/*
- * Z-Star/Vimicro zc301/zc302p/vc30x library
+ * Z-Star/Vimicro zc301/zc302p/vc30x driver
*
- * Copyright (C) 2009-2011 Jean-Francois Moine <http://moinejf.free.fr>
+ * Copyright (C) 2009-2012 Jean-Francois Moine <http://moinejf.free.fr>
* Copyright (C) 2004 2005 2006 Michel Xhaard mxhaard@magic.fr
*
* This program is free software; you can redistribute it and/or modify
@@ -21,8 +21,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#define MODULE_NAME "zc3xx"
-
#include <linux/input.h>
#include "gspca.h"
#include "jpeg.h"
@@ -34,7 +32,7 @@ MODULE_LICENSE("GPL");
static int force_sensor = -1;
-#define QUANT_VAL 1 /* quantization table */
+#define REG08_DEF 3 /* default JPEG compression (70%) */
#include "zc3xx-reg.h"
/* controls */
@@ -46,6 +44,7 @@ enum e_ctrl {
AUTOGAIN,
LIGHTFREQ,
SHARPNESS,
+ QUALITY,
NCTRLS /* number of controls */
};
@@ -57,10 +56,10 @@ struct sd {
struct gspca_ctrl ctrls[NCTRLS];
- u8 quality; /* image quality */
-#define QUALITY_MIN 50
-#define QUALITY_MAX 80
-#define QUALITY_DEF 70
+ struct work_struct work;
+ struct workqueue_struct *work_thread;
+
+ u8 reg08; /* webcam compression quality */
u8 bridge;
u8 sensor; /* Type of image sensor chip */
@@ -101,6 +100,7 @@ static void setexposure(struct gspca_dev *gspca_dev);
static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
static void setlightfreq(struct gspca_dev *gspca_dev);
static void setsharpness(struct gspca_dev *gspca_dev);
+static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val);
static const struct ctrl sd_ctrls[NCTRLS] = {
[BRIGHTNESS] = {
@@ -188,6 +188,18 @@ static const struct ctrl sd_ctrls[NCTRLS] = {
},
.set_control = setsharpness
},
+[QUALITY] = {
+ {
+ .id = V4L2_CID_JPEG_COMPRESSION_QUALITY,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Compression Quality",
+ .minimum = 40,
+ .maximum = 70,
+ .step = 1,
+ .default_value = 70 /* updated in sd_init() */
+ },
+ .set = sd_setquality
+ },
};
static const struct v4l2_pix_format vga_mode[] = {
@@ -229,6 +241,9 @@ static const struct v4l2_pix_format sif_mode[] = {
.priv = 0},
};
+/* bridge reg08 -> JPEG quality conversion table */
+static u8 jpeg_qual[] = {40, 50, 60, 70, /*80*/};
+
/* usb exchanges */
struct usb_action {
u8 req;
@@ -3894,7 +3909,6 @@ static const struct usb_action pas106b_Initial[] = { /* 352x288 */
/* Gains */
{0xa0, 0x20, ZC3XX_R1A9_DIGITALLIMITDIFF},
{0xa0, 0x26, ZC3XX_R1AA_DIGITALGAINSTEP},
- {0xa0, 0xa0, ZC3XX_R11D_GLOBALGAIN},
{0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
/* Auto correction */
{0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
@@ -5381,12 +5395,12 @@ static const struct usb_action tas5130c_NoFlikerScale[] = {
{}
};
-static const struct usb_action gc0303_InitialScale[] = {
+/* from usbvm305.inf 0ac8:305b 07/06/15 (3 - tas5130c) */
+static const struct usb_action gc0303_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
- {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,00,cc,
- * 0<->10 */
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */
{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */
{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */
@@ -5405,29 +5419,22 @@ static const struct usb_action gc0303_InitialScale[] = {
* 6<->8 */
{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */
{0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */
- {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */
- {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */
- {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */
- {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */
- {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
-/*?? {0xaa, 0x01, 0x0000}, */
{0xaa, 0x01, 0x0000},
{0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */
{0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */
+ {0xaa, 0x1b, 0x0000},
{0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */
{0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */
{0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */
{0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */
- {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */
- {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */
- {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */
- {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */
- {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */
- {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */
- {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */
- {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */
-/*?? {0xa0, 0x00, 0x0039},
- {0xa1, 0x01, 0x0037}, */
+ {0xaa, 0x0a, 0x0002},
+ {0xaa, 0x0b, 0x0000},
+ {0xaa, 0x0c, 0x0002},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x0e, 0x0002},
+ {0xaa, 0x0f, 0x0000},
+ {0xaa, 0x10, 0x0002},
+ {0xaa, 0x11, 0x0000},
{0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */
{0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa, (e6 -> e8) */
{0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */
@@ -5442,17 +5449,18 @@ static const struct usb_action gc0303_InitialScale[] = {
{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */
{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */
{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */
- {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */
+ {0xa0, 0x58, ZC3XX_R1A8_DIGITALGAIN},
{0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */
{0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */
+ {0xaa, 0x1b, 0x0000},
{}
};
-static const struct usb_action gc0303_Initial[] = {
+static const struct usb_action gc0303_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
- {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc, */
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH}, /* 00,03,02,cc, */
{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW}, /* 00,04,80,cc, */
{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH}, /* 00,05,01,cc, */
@@ -5471,34 +5479,26 @@ static const struct usb_action gc0303_Initial[] = {
* 8<->6 */
{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID}, /* 00,87,10,cc, */
{0xa0, 0x98, ZC3XX_R08B_I2CDEVICEADDR}, /* 00,8b,98,cc, */
- {0xaa, 0x1b, 0x0024}, /* 00,1b,24,aa, */
- {0xdd, 0x00, 0x0080}, /* 00,00,80,dd, */
- {0xaa, 0x1b, 0x0000}, /* 00,1b,00,aa, */
- {0xaa, 0x13, 0x0002}, /* 00,13,02,aa, */
- {0xaa, 0x15, 0x0004}, /* 00,15,04,aa */
-/*?? {0xaa, 0x01, 0x0000}, */
{0xaa, 0x01, 0x0000},
{0xaa, 0x1a, 0x0000}, /* 00,1a,00,aa, */
{0xaa, 0x1c, 0x0017}, /* 00,1c,17,aa, */
+ {0xaa, 0x1b, 0x0000},
{0xa0, 0x82, ZC3XX_R086_EXPTIMEHIGH}, /* 00,86,82,cc, */
{0xa0, 0x83, ZC3XX_R087_EXPTIMEMID}, /* 00,87,83,cc, */
{0xa0, 0x84, ZC3XX_R088_EXPTIMELOW}, /* 00,88,84,cc, */
{0xaa, 0x05, 0x0010}, /* 00,05,10,aa, */
- {0xaa, 0x0a, 0x0000}, /* 00,0a,00,aa, */
- {0xaa, 0x0b, 0x00a0}, /* 00,0b,a0,aa, */
- {0xaa, 0x0c, 0x0000}, /* 00,0c,00,aa, */
- {0xaa, 0x0d, 0x00a0}, /* 00,0d,a0,aa, */
- {0xaa, 0x0e, 0x0000}, /* 00,0e,00,aa, */
- {0xaa, 0x0f, 0x00a0}, /* 00,0f,a0,aa, */
- {0xaa, 0x10, 0x0000}, /* 00,10,00,aa, */
- {0xaa, 0x11, 0x00a0}, /* 00,11,a0,aa, */
-/*?? {0xa0, 0x00, 0x0039},
- {0xa1, 0x01, 0x0037}, */
+ {0xaa, 0x0a, 0x0001},
+ {0xaa, 0x0b, 0x0000},
+ {0xaa, 0x0c, 0x0001},
+ {0xaa, 0x0d, 0x0000},
+ {0xaa, 0x0e, 0x0001},
+ {0xaa, 0x0f, 0x0000},
+ {0xaa, 0x10, 0x0001},
+ {0xaa, 0x11, 0x0000},
{0xaa, 0x16, 0x0001}, /* 00,16,01,aa, */
{0xaa, 0x17, 0x00e8}, /* 00,17,e6,aa (e6 -> e8) */
{0xaa, 0x18, 0x0002}, /* 00,18,02,aa, */
{0xaa, 0x19, 0x0088}, /* 00,19,88,aa, */
- {0xaa, 0x20, 0x0020}, /* 00,20,20,aa, */
{0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /* 01,01,b7,cc, */
{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC}, /* 00,12,05,cc, */
{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0d,cc, */
@@ -5508,36 +5508,37 @@ static const struct usb_action gc0303_Initial[] = {
{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05}, /* 01,cb,13,cc, */
{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE}, /* 02,50,08,cc, */
{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS}, /* 03,01,08,cc, */
- {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN}, /* 01,a8,60,cc, */
+ {0xa0, 0x58, ZC3XX_R1A8_DIGITALGAIN},
{0xa0, 0x61, ZC3XX_R116_RGAIN}, /* 01,16,61,cc, */
{0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */
+ {0xaa, 0x1b, 0x0000},
{}
};
-static const struct usb_action gc0303_50HZScale[] = {
+static const struct usb_action gc0303_50HZ[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
- {0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */
+ {0xaa, 0x84, 0x0063},
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
{0xa0, 0x06, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0d,cc, */
{0xa0, 0xa8, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,50,cc, */
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */
- {0xa0, 0x8e, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */
+ {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,47,cc, */
{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */
{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */
{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */
- {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */
+ {0xa0, 0x48, ZC3XX_R1AA_DIGITALGAINSTEP},
{0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */
{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */
{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */
{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */
{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
- {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */
+ {0xa0, 0x7f, ZC3XX_R18D_YTARGET},
{}
};
-static const struct usb_action gc0303_50HZ[] = {
+static const struct usb_action gc0303_50HZScale[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0003}, /* 00,83,03,aa */
{0xaa, 0x84, 0x0054}, /* 00,84,54,aa */
@@ -5550,21 +5551,21 @@ static const struct usb_action gc0303_50HZ[] = {
{0xa0, 0x0e, ZC3XX_R18C_AEFREEZE}, /* 01,8c,0e,cc, */
{0xa0, 0x15, ZC3XX_R18F_AEUNFREEZE}, /* 01,8f,15,cc, */
{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF}, /* 01,a9,10,cc, */
- {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */
+ {0xa0, 0x48, ZC3XX_R1AA_DIGITALGAINSTEP}, /* 01,aa,24,cc, */
{0xa0, 0x62, ZC3XX_R01D_HSYNC_0}, /* 00,1d,62,cc, */
{0xa0, 0x90, ZC3XX_R01E_HSYNC_1}, /* 00,1e,90,cc, */
{0xa0, 0xc8, ZC3XX_R01F_HSYNC_2}, /* 00,1f,c8,cc, */
{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */
{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
- {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */
+ {0xa0, 0x7f, ZC3XX_R18D_YTARGET},
{}
};
-static const struct usb_action gc0303_60HZScale[] = {
+static const struct usb_action gc0303_60HZ[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
- {0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
- {0xaa, 0x84, 0x0062}, /* 00,84,62,aa */
+ {0xaa, 0x83, 0x0000},
+ {0xaa, 0x84, 0x003b},
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
{0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */
{0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */
@@ -5581,14 +5582,14 @@ static const struct usb_action gc0303_60HZScale[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,20,ff,cc, */
{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,1d,58,cc, */
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
- {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,8d,78,cc */
+ {0xa0, 0x80, ZC3XX_R18D_YTARGET},
{}
};
-static const struct usb_action gc0303_60HZ[] = {
+static const struct usb_action gc0303_60HZScale[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
- {0xaa, 0x83, 0x0002}, /* 00,83,02,aa */
- {0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */
+ {0xaa, 0x83, 0x0000},
+ {0xaa, 0x84, 0x0076},
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
{0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,1,0b,cc, */
{0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,2,10,cc, */
@@ -5605,18 +5606,18 @@ static const struct usb_action gc0303_60HZ[] = {
{0xa0, 0xff, ZC3XX_R020_HSYNC_3}, /* 00,0,ff,cc, */
{0xa0, 0x58, ZC3XX_R11D_GLOBALGAIN}, /* 01,d,58,cc, */
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE}, /* 01,80,42,cc, */
- {0xa0, 0x78, ZC3XX_R18D_YTARGET}, /* 01,d,78,cc */
+ {0xa0, 0x80, ZC3XX_R18D_YTARGET},
{}
};
-static const struct usb_action gc0303_NoFlikerScale[] = {
+static const struct usb_action gc0303_NoFliker[] = {
{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
{0xaa, 0x84, 0x0020}, /* 00,84,20,aa */
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,0,00,cc, */
- {0xa0, 0x05, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,05,cc, */
- {0xa0, 0x88, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,88,cc, */
+ {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW},
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */
{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */
@@ -5631,14 +5632,14 @@ static const struct usb_action gc0303_NoFlikerScale[] = {
{}
};
-static const struct usb_action gc0303_NoFliker[] = {
+static const struct usb_action gc0303_NoFlikerScale[] = {
{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
{0xaa, 0x84, 0x0020}, /* 00,84,20,aa */
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 01,90,00,cc, */
- {0xa0, 0x0b, ZC3XX_R191_EXPOSURELIMITMID}, /* 01,91,0b,cc, */
- {0xa0, 0x10, ZC3XX_R192_EXPOSURELIMITLOW}, /* 01,92,10,cc, */
+ {0xa0, 0x00, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x48, ZC3XX_R192_EXPOSURELIMITLOW},
{0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH}, /* 01,95,00,cc, */
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc, */
{0xa0, 0x10, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,10,cc, */
@@ -5653,7 +5654,7 @@ static const struct usb_action gc0303_NoFliker[] = {
{}
};
-static u8 reg_r_i(struct gspca_dev *gspca_dev,
+static u8 reg_r(struct gspca_dev *gspca_dev,
u16 index)
{
int ret;
@@ -5668,24 +5669,14 @@ static u8 reg_r_i(struct gspca_dev *gspca_dev,
index, gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- pr_err("reg_r_i err %d\n", ret);
+ pr_err("reg_r err %d\n", ret);
gspca_dev->usb_err = ret;
return 0;
}
return gspca_dev->usb_buf[0];
}
-static u8 reg_r(struct gspca_dev *gspca_dev,
- u16 index)
-{
- u8 ret;
-
- ret = reg_r_i(gspca_dev, index);
- PDEBUG(D_USBI, "reg r [%04x] -> %02x", index, ret);
- return ret;
-}
-
-static void reg_w_i(struct gspca_dev *gspca_dev,
+static void reg_w(struct gspca_dev *gspca_dev,
u8 value,
u16 index)
{
@@ -5705,14 +5696,6 @@ static void reg_w_i(struct gspca_dev *gspca_dev,
}
}
-static void reg_w(struct gspca_dev *gspca_dev,
- u8 value,
- u16 index)
-{
- PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value);
- reg_w_i(gspca_dev, value, index);
-}
-
static u16 i2c_read(struct gspca_dev *gspca_dev,
u8 reg)
{
@@ -5721,16 +5704,14 @@ static u16 i2c_read(struct gspca_dev *gspca_dev,
if (gspca_dev->usb_err < 0)
return 0;
- reg_w_i(gspca_dev, reg, 0x0092);
- reg_w_i(gspca_dev, 0x02, 0x0090); /* <- read command */
+ reg_w(gspca_dev, reg, 0x0092);
+ reg_w(gspca_dev, 0x02, 0x0090); /* <- read command */
msleep(20);
- retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */
+ retbyte = reg_r(gspca_dev, 0x0091); /* read status */
if (retbyte != 0x00)
pr_err("i2c_r status error %02x\n", retbyte);
- retval = reg_r_i(gspca_dev, 0x0095); /* read Lowbyte */
- retval |= reg_r_i(gspca_dev, 0x0096) << 8; /* read Hightbyte */
- PDEBUG(D_USBI, "i2c r [%02x] -> %04x (%02x)",
- reg, retval, retbyte);
+ retval = reg_r(gspca_dev, 0x0095); /* read Lowbyte */
+ retval |= reg_r(gspca_dev, 0x0096) << 8; /* read Hightbyte */
return retval;
}
@@ -5743,16 +5724,14 @@ static u8 i2c_write(struct gspca_dev *gspca_dev,
if (gspca_dev->usb_err < 0)
return 0;
- reg_w_i(gspca_dev, reg, 0x92);
- reg_w_i(gspca_dev, valL, 0x93);
- reg_w_i(gspca_dev, valH, 0x94);
- reg_w_i(gspca_dev, 0x01, 0x90); /* <- write command */
+ reg_w(gspca_dev, reg, 0x92);
+ reg_w(gspca_dev, valL, 0x93);
+ reg_w(gspca_dev, valH, 0x94);
+ reg_w(gspca_dev, 0x01, 0x90); /* <- write command */
msleep(1);
- retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */
+ retbyte = reg_r(gspca_dev, 0x0091); /* read status */
if (retbyte != 0x00)
pr_err("i2c_w status error %02x\n", retbyte);
- PDEBUG(D_USBO, "i2c w [%02x] = %02x%02x (%02x)",
- reg, valH, valL, retbyte);
return retbyte;
}
@@ -5809,7 +5788,7 @@ static void setmatrix(struct gspca_dev *gspca_dev)
static const u8 tas5130c_matrix[9] =
{0x68, 0xec, 0xec, 0xec, 0x68, 0xec, 0xec, 0xec, 0x68};
static const u8 gc0303_matrix[9] =
- {0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b};
+ {0x6c, 0xea, 0xea, 0xea, 0x6c, 0xea, 0xea, 0xea, 0x6c};
static const u8 *matrix_tb[SENSOR_MAX] = {
[SENSOR_ADCM2700] = adcm2700_matrix,
[SENSOR_CS2102] = ov7620_matrix,
@@ -5919,6 +5898,8 @@ static void getexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (sd->sensor != SENSOR_HV7131R)
+ return;
sd->ctrls[EXPOSURE].val = (i2c_read(gspca_dev, 0x25) << 9)
| (i2c_read(gspca_dev, 0x26) << 1)
| (i2c_read(gspca_dev, 0x27) >> 7);
@@ -5929,6 +5910,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
int val;
+ if (sd->sensor != SENSOR_HV7131R)
+ return;
val = sd->ctrls[EXPOSURE].val;
i2c_write(gspca_dev, 0x25, val >> 9, 0x00);
i2c_write(gspca_dev, 0x26, val >> 1, 0x00);
@@ -5938,32 +5921,20 @@ static void setexposure(struct gspca_dev *gspca_dev)
static void setquality(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 frxt;
+ s8 reg07;
+ reg07 = 0;
switch (sd->sensor) {
- case SENSOR_ADCM2700:
- case SENSOR_GC0305:
- case SENSOR_HV7131B:
- case SENSOR_HV7131R:
case SENSOR_OV7620:
+ reg07 = 0x30;
+ break;
+ case SENSOR_HV7131R:
case SENSOR_PAS202B:
- case SENSOR_PO2030:
- return;
+ return; /* done by work queue */
}
-/*fixme: is it really 0008 0007 0018 for all other sensors? */
- reg_w(gspca_dev, QUANT_VAL, 0x0008);
- frxt = 0x30;
- reg_w(gspca_dev, frxt, 0x0007);
-#if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2
- frxt = 0xff;
-#elif QUANT_VAL == 3
- frxt = 0xf0;
-#elif QUANT_VAL == 4
- frxt = 0xe0;
-#else
- frxt = 0x20;
-#endif
- reg_w(gspca_dev, frxt, 0x0018);
+ reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
+ if (reg07 != 0)
+ reg_w(gspca_dev, reg07, 0x0007);
}
/* Matches the sensor's internal frame rate to the lighting frequency.
@@ -6097,6 +6068,115 @@ static void setautogain(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, autoval, 0x0180);
}
+/* update the transfer parameters */
+/* This function is executed from a work queue. */
+/* The exact use of the bridge registers 07 and 08 is not known.
+ * The following algorithm has been adapted from ms-win traces */
+static void transfer_update(struct work_struct *work)
+{
+ struct sd *sd = container_of(work, struct sd, work);
+ struct gspca_dev *gspca_dev = &sd->gspca_dev;
+ int change, good;
+ u8 reg07, reg11;
+
+ /* synchronize with the main driver and initialize the registers */
+ mutex_lock(&gspca_dev->usb_lock);
+ reg07 = 0; /* max */
+ reg_w(gspca_dev, reg07, 0x0007);
+ reg_w(gspca_dev, sd->reg08, ZC3XX_R008_CLOCKSETTING);
+ mutex_unlock(&gspca_dev->usb_lock);
+
+ good = 0;
+ for (;;) {
+ msleep(100);
+
+ /* get the transfer status */
+ /* the bit 0 of the bridge register 11 indicates overflow */
+ mutex_lock(&gspca_dev->usb_lock);
+ if (!gspca_dev->present || !gspca_dev->streaming)
+ goto err;
+ reg11 = reg_r(gspca_dev, 0x0011);
+ if (gspca_dev->usb_err < 0
+ || !gspca_dev->present || !gspca_dev->streaming)
+ goto err;
+
+ change = reg11 & 0x01;
+ if (change) { /* overflow */
+ switch (reg07) {
+ case 0: /* max */
+ reg07 = sd->sensor == SENSOR_HV7131R
+ ? 0x30 : 0x32;
+ if (sd->reg08 != 0) {
+ change = 3;
+ sd->reg08--;
+ }
+ break;
+ case 0x32:
+ reg07 -= 4;
+ break;
+ default:
+ reg07 -= 2;
+ break;
+ case 2:
+ change = 0; /* already min */
+ break;
+ }
+ good = 0;
+ } else { /* no overflow */
+ if (reg07 != 0) { /* if not max */
+ good++;
+ if (good >= 10) {
+ good = 0;
+ change = 1;
+ reg07 += 2;
+ switch (reg07) {
+ case 0x30:
+ if (sd->sensor == SENSOR_PAS202B)
+ reg07 += 2;
+ break;
+ case 0x32:
+ case 0x34:
+ reg07 = 0;
+ break;
+ }
+ }
+ } else { /* reg07 max */
+ if (sd->reg08 < sizeof jpeg_qual - 1) {
+ good++;
+ if (good > 10) {
+ sd->reg08++;
+ change = 2;
+ }
+ }
+ }
+ }
+ if (change) {
+ if (change & 1) {
+ reg_w(gspca_dev, reg07, 0x0007);
+ if (gspca_dev->usb_err < 0
+ || !gspca_dev->present
+ || !gspca_dev->streaming)
+ goto err;
+ }
+ if (change & 2) {
+ reg_w(gspca_dev, sd->reg08,
+ ZC3XX_R008_CLOCKSETTING);
+ if (gspca_dev->usb_err < 0
+ || !gspca_dev->present
+ || !gspca_dev->streaming)
+ goto err;
+ sd->ctrls[QUALITY].val = jpeg_qual[sd->reg08];
+ jpeg_set_qual(sd->jpeg_hdr,
+ jpeg_qual[sd->reg08]);
+ }
+ }
+ mutex_unlock(&gspca_dev->usb_lock);
+ }
+ return;
+err:
+ mutex_unlock(&gspca_dev->usb_lock);
+}
+
static void send_unknown(struct gspca_dev *gspca_dev, int sensor)
{
reg_w(gspca_dev, 0x01, 0x0000); /* bridge reset */
@@ -6424,11 +6504,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor = id->driver_info;
gspca_dev->cam.ctrls = sd->ctrls;
- sd->quality = QUALITY_DEF;
+ sd->reg08 = REG08_DEF;
- /* if USB 1.1, let some bandwidth for the audio device */
- if (gspca_dev->audio && gspca_dev->dev->speed < USB_SPEED_HIGH)
- gspca_dev->nbalt--;
+ INIT_WORK(&sd->work, transfer_update);
return 0;
}
@@ -6481,6 +6559,27 @@ static int sd_init(struct gspca_dev *gspca_dev)
[SENSOR_PO2030] = 1,
[SENSOR_TAS5130C] = 1,
};
+ static const u8 reg08_tb[SENSOR_MAX] = {
+ [SENSOR_ADCM2700] = 1,
+ [SENSOR_CS2102] = 3,
+ [SENSOR_CS2102K] = 3,
+ [SENSOR_GC0303] = 2,
+ [SENSOR_GC0305] = 3,
+ [SENSOR_HDCS2020] = 1,
+ [SENSOR_HV7131B] = 3,
+ [SENSOR_HV7131R] = 3,
+ [SENSOR_ICM105A] = 3,
+ [SENSOR_MC501CB] = 3,
+ [SENSOR_MT9V111_1] = 3,
+ [SENSOR_MT9V111_3] = 3,
+ [SENSOR_OV7620] = 1,
+ [SENSOR_OV7630C] = 3,
+ [SENSOR_PAS106] = 3,
+ [SENSOR_PAS202B] = 3,
+ [SENSOR_PB0330] = 3,
+ [SENSOR_PO2030] = 2,
+ [SENSOR_TAS5130C] = 3,
+ };
sensor = zcxx_probeSensor(gspca_dev);
if (sensor >= 0)
@@ -6545,7 +6644,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
case 0x0e:
PDEBUG(D_PROBE, "Find Sensor PAS202B");
sd->sensor = SENSOR_PAS202B;
-/* sd->sharpness = 1; */
break;
case 0x0f:
PDEBUG(D_PROBE, "Find Sensor PAS106");
@@ -6633,13 +6731,21 @@ static int sd_init(struct gspca_dev *gspca_dev)
}
sd->ctrls[GAMMA].def = gamma[sd->sensor];
+ sd->reg08 = reg08_tb[sd->sensor];
+ sd->ctrls[QUALITY].def = jpeg_qual[sd->reg08];
+ sd->ctrls[QUALITY].min = jpeg_qual[0];
+ sd->ctrls[QUALITY].max = jpeg_qual[ARRAY_SIZE(jpeg_qual) - 1];
switch (sd->sensor) {
case SENSOR_HV7131R:
+ gspca_dev->ctrl_dis = (1 << QUALITY);
break;
case SENSOR_OV7630C:
gspca_dev->ctrl_dis = (1 << LIGHTFREQ) | (1 << EXPOSURE);
break;
+ case SENSOR_PAS202B:
+ gspca_dev->ctrl_dis = (1 << QUALITY) | (1 << EXPOSURE);
+ break;
default:
gspca_dev->ctrl_dis = (1 << EXPOSURE);
break;
@@ -6702,7 +6808,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* create the JPEG header */
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
- jpeg_set_qual(sd->jpeg_hdr, sd->quality);
mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
switch (sd->sensor) {
@@ -6778,10 +6883,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_r(gspca_dev, 0x0180); /* from win */
reg_w(gspca_dev, 0x00, 0x0180);
break;
- default:
- setquality(gspca_dev);
- break;
}
+ setquality(gspca_dev);
+ jpeg_set_qual(sd->jpeg_hdr, jpeg_qual[sd->reg08]);
setlightfreq(gspca_dev);
switch (sd->sensor) {
@@ -6793,8 +6897,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x40, 0x0117);
break;
case SENSOR_HV7131R:
- if (!sd->ctrls[AUTOGAIN].val)
- setexposure(gspca_dev);
+ setexposure(gspca_dev);
reg_w(gspca_dev, 0x00, ZC3XX_R1A7_CALCGLOBALMEAN);
break;
case SENSOR_GC0305:
@@ -6819,13 +6922,19 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
setautogain(gspca_dev);
- switch (sd->sensor) {
- case SENSOR_PO2030:
- msleep(50);
- reg_w(gspca_dev, 0x00, 0x0007); /* (from win traces) */
- reg_w(gspca_dev, 0x02, ZC3XX_R008_CLOCKSETTING);
- break;
+
+ /* start the transfer update thread if needed */
+ if (gspca_dev->usb_err >= 0) {
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ case SENSOR_PAS202B:
+ sd->work_thread =
+ create_singlethread_workqueue(KBUILD_MODNAME);
+ queue_work(sd->work_thread, &sd->work);
+ break;
+ }
}
+
return gspca_dev->usb_err;
}
@@ -6834,6 +6943,12 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (sd->work_thread != NULL) {
+ mutex_unlock(&gspca_dev->usb_lock);
+ destroy_workqueue(sd->work_thread);
+ mutex_lock(&gspca_dev->usb_lock);
+ sd->work_thread = NULL;
+ }
if (!gspca_dev->present)
return;
send_unknown(gspca_dev, sd->sensor);
@@ -6910,19 +7025,33 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
+static int sd_setquality(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(jpeg_qual) - 1; i++) {
+ if (val <= jpeg_qual[i])
+ break;
+ }
+ if (i > 0
+ && i == sd->reg08
+ && val < jpeg_qual[sd->reg08])
+ i--;
+ sd->reg08 = i;
+ sd->ctrls[QUALITY].val = jpeg_qual[i];
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->ctrls[QUALITY].val);
+ return gspca_dev->usb_err;
+}
+
static int sd_set_jcomp(struct gspca_dev *gspca_dev,
struct v4l2_jpegcompression *jcomp)
{
struct sd *sd = (struct sd *) gspca_dev;
- 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);
+ sd_setquality(gspca_dev, jcomp->quality);
+ jcomp->quality = sd->ctrls[QUALITY].val;
return gspca_dev->usb_err;
}
@@ -6932,7 +7061,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
memset(jcomp, 0, sizeof *jcomp);
- jcomp->quality = sd->quality;
+ jcomp->quality = sd->ctrls[QUALITY].val;
jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
| V4L2_JPEG_MARKER_DQT;
return 0;
@@ -6955,7 +7084,7 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
#endif
static const struct sd_desc sd_desc = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.ctrls = sd_ctrls,
.nctrls = ARRAY_SIZE(sd_ctrls),
.config = sd_config,
@@ -7040,7 +7169,7 @@ static int sd_probe(struct usb_interface *intf,
/* USB driver */
static struct usb_driver sd_driver = {
- .name = MODULE_NAME,
+ .name = KBUILD_MODNAME,
.id_table = device_table,
.probe = sd_probe,
.disconnect = gspca_disconnect,