summaryrefslogtreecommitdiff
path: root/linux/drivers/media/video/gspca/sonixj.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/drivers/media/video/gspca/sonixj.c')
-rw-r--r--linux/drivers/media/video/gspca/sonixj.c205
1 files changed, 137 insertions, 68 deletions
diff --git a/linux/drivers/media/video/gspca/sonixj.c b/linux/drivers/media/video/gspca/sonixj.c
index 36d6f50be..a4c935d69 100644
--- a/linux/drivers/media/video/gspca/sonixj.c
+++ b/linux/drivers/media/video/gspca/sonixj.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "sonixj"
#include "gspca.h"
-#define QUANT_VAL 4 /* quantization table */
#include "jpeg.h"
#define V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0)
@@ -47,6 +46,13 @@ struct sd {
u8 gamma;
u8 vflip; /* ov7630/ov7648 only */
u8 infrared; /* mt9v111 only */
+ u8 quality; /* image quality */
+#define QUALITY_MIN 60
+#define QUALITY_MAX 95
+#define QUALITY_DEF 80
+ u8 jpegqual; /* webcam quality */
+
+ u8 reg18;
s8 ag_cnt;
#define AG_CNT_START 13
@@ -56,7 +62,6 @@ struct sd {
#define BRIDGE_SN9C105 1
#define BRIDGE_SN9C110 2
#define BRIDGE_SN9C120 3
-#define BRIDGE_SN9C325 4
u8 sensor; /* Type of image sensor chip */
#define SENSOR_HV7131R 0
#define SENSOR_MI0360 1
@@ -68,6 +73,8 @@ struct sd {
#define SENSOR_OV7660 7
#define SENSOR_SP80708 8
u8 i2c_base;
+
+ u8 *jpeg_hdr;
};
/* V4L2 controls supported by the driver */
@@ -350,9 +357,9 @@ static const u8 sn_ov7648[0x1c] = {
static const u8 sn_ov7660[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
- 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20,
+ 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00,
/* reg8 reg9 rega regb regc regd rege regf */
- 0x81, 0x21, 0x07, 0x00, 0x00, 0x00, 0x00, 0x10,
+ 0x81, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
0x03, 0x00, 0x01, 0x01, 0x08, 0x28, 0x1e, 0x20,
/* reg18 reg19 reg1a reg1b */
@@ -757,6 +764,7 @@ static const u8 ov7660_sensor_init[][8] = {
{0xc1, 0x21, 0x88, 0xaf, 0xc7, 0xdf, 0x00, 0x10}, /* gamma curve */
{0xc1, 0x21, 0x8b, 0x99, 0x99, 0xcf, 0x00, 0x10}, /* reserved */
{0xb1, 0x21, 0x92, 0x00, 0x00, 0x00, 0x00, 0x10}, /* DM_LNL/H */
+ {0xb1, 0x21, 0xa1, 0x00, 0x00, 0x00, 0x00, 0x10},
/****** (some exchanges in the win trace) ******/
{0xa1, 0x21, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x10}, /* MVFP */
/* bits[3..0]reserved */
@@ -867,25 +875,6 @@ static const u8 sp80708_sensor_init[][8] = {
{}
};
-static const u8 qtable4[] = {
- 0x06, 0x04, 0x04, 0x06, 0x04, 0x04, 0x06, 0x06,
- 0x06, 0x06, 0x08, 0x06, 0x06, 0x08, 0x0a, 0x11,
- 0x0a, 0x0a, 0x08, 0x08, 0x0a, 0x15, 0x0f, 0x0f,
- 0x0c, 0x11, 0x19, 0x15, 0x19, 0x19, 0x17, 0x15,
- 0x17, 0x17, 0x1b, 0x1d, 0x25, 0x21, 0x1b, 0x1d,
- 0x23, 0x1d, 0x17, 0x17, 0x21, 0x2e, 0x21, 0x23,
- 0x27, 0x29, 0x2c, 0x2c, 0x2c, 0x19, 0x1f, 0x30,
- 0x32, 0x2e, 0x29, 0x32, 0x25, 0x29, 0x2c, 0x29,
- 0x06, 0x08, 0x08, 0x0a, 0x08, 0x0a, 0x13, 0x0a,
- 0x0a, 0x13, 0x29, 0x1b, 0x17, 0x1b, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29,
- 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29, 0x29
-};
-
/* read <len> bytes to gspca_dev->usb_buf */
static void reg_r(struct gspca_dev *gspca_dev,
u16 value, int len)
@@ -1084,9 +1073,13 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
const u8 *reg9a;
static const u8 reg9a_def[] =
- {0x08, 0x40, 0x20, 0x10, 0x00, 0x04};
- static const u8 reg9a_sn9c325[] =
- {0x0a, 0x40, 0x38, 0x30, 0x00, 0x20};
+#if 1
+ {0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
+#else
+ {0x00, 0x40, 0x20, 0x10, 0x00, 0x04};
+#endif
+ static const u8 reg9a_spec[] =
+ {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
static const u8 regd4[] = {0x60, 0x00, 0x00};
reg_w1(gspca_dev, 0xf1, 0x00);
@@ -1100,9 +1093,10 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5); /* jfm len was 3 */
- switch (sd->bridge) {
- case BRIDGE_SN9C325:
- reg9a = reg9a_sn9c325;
+ switch (sd->sensor) {
+ case SENSOR_OV7660:
+ case SENSOR_SP80708:
+ reg9a = reg9a_spec;
break;
default:
reg9a = reg9a_def;
@@ -1127,32 +1121,24 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
reg_w1(gspca_dev, 0x17, 0x64);
reg_w1(gspca_dev, 0x01, 0x42);
break;
-#if 1
-/*jfm: from win trace */
case SENSOR_OV7630:
reg_w1(gspca_dev, 0x01, 0x61);
reg_w1(gspca_dev, 0x17, 0xe2);
reg_w1(gspca_dev, 0x01, 0x60);
reg_w1(gspca_dev, 0x01, 0x40);
break;
-#endif
case SENSOR_OV7648:
reg_w1(gspca_dev, 0x01, 0x63);
reg_w1(gspca_dev, 0x17, 0x20);
+ reg_w1(gspca_dev, 0x01, 0x62);
reg_w1(gspca_dev, 0x01, 0x42);
break;
-#if 1
-/*jfm: from win trace */
case SENSOR_OV7660:
- if (sd->bridge == BRIDGE_SN9C120) {
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- }
- /* fall thru */
-#endif
+ reg_w1(gspca_dev, 0x01, 0x61);
+ reg_w1(gspca_dev, 0x17, 0x20);
+ reg_w1(gspca_dev, 0x01, 0x60);
+ reg_w1(gspca_dev, 0x01, 0x40);
+ break;
case SENSOR_SP80708:
reg_w1(gspca_dev, 0x01, 0x63);
reg_w1(gspca_dev, 0x17, 0x20);
@@ -1161,6 +1147,9 @@ static int configure_gpio(struct gspca_dev *gspca_dev,
mdelay(100);
reg_w1(gspca_dev, 0x02, 0x62);
break;
+/* case SENSOR_HV7131R: */
+/* case SENSOR_MI0360: */
+/* case SENSOR_MO4000: */
default:
reg_w1(gspca_dev, 0x01, 0x43);
reg_w1(gspca_dev, 0x17, 0x61);
@@ -1307,6 +1296,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
+ cam->npkt = 24; /* 24 packets per ISOC message */
sd->bridge = id->driver_info >> 16;
sd->sensor = id->driver_info >> 8;
@@ -1325,6 +1315,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
else
sd->vflip = 1;
sd->infrared = INFRARED_DEF;
+ sd->quality = QUALITY_DEF;
+ sd->jpegqual = 80;
gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
return 0;
@@ -1642,12 +1634,49 @@ static void setinfrared(struct sd *sd)
#endif
}
+static void setjpegqual(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, sc;
+
+ if (sd->jpegqual < 50)
+ sc = 5000 / sd->jpegqual;
+ else
+ sc = 200 - sd->jpegqual * 2;
+#if USB_BUF_SZ < 64
+#error "No room enough in usb_buf for quantization table"
+#endif
+ for (i = 0; i < 64; i++)
+ gspca_dev->usb_buf[i] =
+ (jpeg_head[JPEG_QT0_OFFSET + i] * sc + 50) / 100;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0x0100, 0,
+ gspca_dev->usb_buf, 64,
+ 500);
+ for (i = 0; i < 64; i++)
+ gspca_dev->usb_buf[i] =
+ (jpeg_head[JPEG_QT1_OFFSET + i] * sc + 50) / 100;
+ usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
+ 0x0140, 0,
+ gspca_dev->usb_buf, 64,
+ 500);
+
+ sd->reg18 ^= 0x40;
+ reg_w1(gspca_dev, 0x18, sd->reg18);
+}
+
/* -- start the camera -- */
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
- u8 reg1, reg17, reg18;
+ u8 reg1, reg17;
const u8 *sn9c1xx;
int mode;
static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
@@ -1656,6 +1685,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
static const u8 CE_ov76xx[] =
{ 0x32, 0xdd, 0x32, 0xdd };
+ /* create the JPEG header */
+ sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x21); /* JPEG 422 */
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+
sn9c1xx = sn_tb[(int) sd->sensor];
configure_gpio(gspca_dev, sn9c1xx);
@@ -1681,15 +1716,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_OV7648:
reg17 = 0x20;
break;
-#if 1
-/*jfm: from win trace */
case SENSOR_OV7660:
- if (sd->bridge == BRIDGE_SN9C120) {
- reg17 = 0xa0;
- break;
- }
- /* fall thru */
-#endif
+ reg17 = 0xa0;
+ break;
default:
reg17 = 0x60;
break;
@@ -1714,16 +1743,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x9a, 0x0a);
reg_w1(gspca_dev, 0x99, 0x60);
break;
+ case SENSOR_OV7660:
+ reg_w1(gspca_dev, 0x9a, 0x05);
+ if (sd->bridge == BRIDGE_SN9C105)
+ reg_w1(gspca_dev, 0x99, 0xff);
+ else
+ reg_w1(gspca_dev, 0x99, 0x5b);
+ break;
case SENSOR_SP80708:
reg_w1(gspca_dev, 0x9a, 0x05);
reg_w1(gspca_dev, 0x99, 0x59);
break;
- case SENSOR_OV7660:
- if (sd->bridge == BRIDGE_SN9C120) {
- reg_w1(gspca_dev, 0x9a, 0x05);
- break;
- }
- /* fall thru */
default:
reg_w1(gspca_dev, 0x9a, 0x08);
reg_w1(gspca_dev, 0x99, 0x59);
@@ -1816,13 +1846,9 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
/* here change size mode 0 -> VGA; 1 -> CIF */
- reg18 = sn9c1xx[0x18] | (mode << 4);
- reg_w1(gspca_dev, 0x18, reg18 | 0x40);
-
- reg_w(gspca_dev, 0x0100, qtable4, 0x40);
- reg_w(gspca_dev, 0x0140, qtable4 + 0x40, 0x40);
-
- reg_w1(gspca_dev, 0x18, reg18);
+ sd->reg18 = sn9c1xx[0x18] | (mode << 4) | 0x40;
+ reg_w1(gspca_dev, 0x18, sd->reg18);
+ setjpegqual(gspca_dev);
reg_w1(gspca_dev, 0x17, reg17);
reg_w1(gspca_dev, 0x01, reg1);
@@ -1884,6 +1910,13 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0xf1, 0x00);
}
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ kfree(sd->jpeg_hdr);
+}
+
static void do_autogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1967,7 +2000,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
if (gspca_dev->last_packet_type == LAST_PACKET) {
/* put the JPEG 422 header */
- jpeg_put_header(gspca_dev, frame, 0x21);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, frame,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
}
gspca_frame_add(gspca_dev, INTER_PACKET, frame, data, len);
}
@@ -2134,6 +2168,34 @@ static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_set_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (jcomp->quality < QUALITY_MIN)
+ sd->quality = QUALITY_MIN;
+ else if (jcomp->quality > QUALITY_MAX)
+ sd->quality = QUALITY_MAX;
+ else
+ sd->quality = jcomp->quality;
+ if (gspca_dev->streaming)
+ jpeg_set_qual(sd->jpeg_hdr, sd->quality);
+ return 0;
+}
+
+static int sd_get_jcomp(struct gspca_dev *gspca_dev,
+ struct v4l2_jpegcompression *jcomp)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ memset(jcomp, 0, sizeof *jcomp);
+ jcomp->quality = sd->quality;
+ jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
+ | V4L2_JPEG_MARKER_DQT;
+ return 0;
+}
+
/* sub-driver description */
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
@@ -2143,8 +2205,11 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
+ .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
+ .get_jcomp = sd_get_jcomp,
+ .set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
@@ -2159,12 +2224,11 @@ static const __devinitdata struct usb_device_id device_table[] = {
#endif
{USB_DEVICE(0x045e, 0x00f5), BSI(SN9C105, OV7660, 0x21)},
{USB_DEVICE(0x045e, 0x00f7), BSI(SN9C105, OV7660, 0x21)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0471, 0x0327), BSI(SN9C105, MI0360, 0x5d)},
-#endif
{USB_DEVICE(0x0471, 0x0328), BSI(SN9C105, MI0360, 0x5d)},
{USB_DEVICE(0x0471, 0x0330), BSI(SN9C105, MI0360, 0x5d)},
{USB_DEVICE(0x06f8, 0x3004), BSI(SN9C105, OV7660, 0x21)},
+ {USB_DEVICE(0x06f8, 0x3008), BSI(SN9C105, OV7660, 0x21)},
{USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, HV7131R, 0x11)},
/* bw600.inf:
{USB_DEVICE(0x0c45, 0x6040), BSI(SN9C102P, MI0360, 0x5d)}, */
@@ -2183,7 +2247,12 @@ static const __devinitdata struct usb_device_id device_table[] = {
#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x60fe), BSI(SN9C105, OV7630, 0x21)},
#endif
+ {USB_DEVICE(0x0c45, 0x6100), BSI(SN9C120, MI0360, 0x5d)}, /*sn9c128*/
/* {USB_DEVICE(0x0c45, 0x6108), BSI(SN9C120, OM6801, 0x??)}, */
+ {USB_DEVICE(0x0c45, 0x610a), BSI(SN9C120, OV7648, 0x21)}, /*sn9c128*/
+ {USB_DEVICE(0x0c45, 0x610b), BSI(SN9C120, OV7660, 0x21)}, /*sn9c128*/
+ {USB_DEVICE(0x0c45, 0x610c), BSI(SN9C120, HV7131R, 0x11)}, /*sn9c128*/
+ {USB_DEVICE(0x0c45, 0x610e), BSI(SN9C120, OV7630, 0x21)}, /*sn9c128*/
/* {USB_DEVICE(0x0c45, 0x6122), BSI(SN9C110, ICM105C, 0x??)}, */
/* {USB_DEVICE(0x0c45, 0x6123), BSI(SN9C110, SanyoCCD, 0x??)}, */
{USB_DEVICE(0x0c45, 0x6128), BSI(SN9C110, OM6802, 0x21)}, /*sn9c325?*/