diff options
Diffstat (limited to 'drivers/media/video/gspca/zc3xx.c')
-rw-r--r-- | drivers/media/video/gspca/zc3xx.c | 443 |
1 files changed, 286 insertions, 157 deletions
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c index 0202fead6b97..7d9a4f1be9dc 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, |