diff options
Diffstat (limited to 'linux/drivers/media/video/gspca/sonixj.c')
-rw-r--r-- | linux/drivers/media/video/gspca/sonixj.c | 205 |
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?*/ |