linux/drivers/media/usb/gspca/gl860/gl860-ov2640.c
<<
>>
Prefs
   1/* Subdriver for the GL860 chip with the OV2640 sensor
   2 * Author Olivier LORIN, from Malmostoso's logs
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License as published by
   6 * the Free Software Foundation; either version 2 of the License, or
   7 * any later version.
   8 *
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16 */
  17
  18/* Sensor : OV2640 */
  19
  20#include "gl860.h"
  21
  22static u8 dat_init1[] = "\x00\x41\x07\x6a\x06\x61\x0d\x6a" "\x10\x10\xc1\x01";
  23
  24static u8 c61[] = {0x61}; /* expected */
  25static u8 c51[] = {0x51}; /* expected */
  26static u8 c50[] = {0x50}; /* expected */
  27static u8 c28[] = {0x28}; /* expected */
  28static u8 ca8[] = {0xa8}; /* expected */
  29
  30static u8 dat_post[] =
  31        "\x00\x41\x07\x6a\x06\xef\x0d\x6a" "\x10\x10\xc1\x01";
  32
  33static u8 dat_640[]  = "\xd0\x01\xd1\x08\xd2\xe0\xd3\x02\xd4\x10\xd5\x81";
  34static u8 dat_800[]  = "\xd0\x01\xd1\x10\xd2\x58\xd3\x02\xd4\x18\xd5\x21";
  35static u8 dat_1280[] = "\xd0\x01\xd1\x18\xd2\xc0\xd3\x02\xd4\x28\xd5\x01";
  36static u8 dat_1600[] = "\xd0\x01\xd1\x20\xd2\xb0\xd3\x02\xd4\x30\xd5\x41";
  37
  38static struct validx tbl_init_at_startup[] = {
  39        {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1},
  40        {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
  41        {0x0050, 0x0000}, {0x0041, 0x0000}, {0x006a, 0x0007}, {0x0061, 0x0006},
  42        {0x006a, 0x000d}, {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1},
  43        {0x0041, 0x00c2}, {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058},
  44        {0x0041, 0x0000}, {0x0061, 0x0000},
  45};
  46
  47static struct validx tbl_common[] = {
  48        {0x6000, 0x00ff}, {0x60ff, 0x002c}, {0x60df, 0x002e}, {0x6001, 0x00ff},
  49        {0x6080, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010},
  50        {0x6035, 0x003c}, {0x6000, 0x0011}, {0x6028, 0x0004}, {0x60e5, 0x0013},
  51        {0x6088, 0x0014}, {0x600c, 0x002c}, {0x6078, 0x0033}, {0x60f7, 0x003b},
  52        {0x6000, 0x003e}, {0x6011, 0x0043}, {0x6010, 0x0016}, {0x6082, 0x0039},
  53        {0x6088, 0x0035}, {0x600a, 0x0022}, {0x6040, 0x0037}, {0x6000, 0x0023},
  54        {0x60a0, 0x0034}, {0x601a, 0x0036}, {0x6002, 0x0006}, {0x60c0, 0x0007},
  55        {0x60b7, 0x000d}, {0x6001, 0x000e}, {0x6000, 0x004c}, {0x6081, 0x004a},
  56        {0x6099, 0x0021}, {0x6002, 0x0009}, {0x603e, 0x0024}, {0x6034, 0x0025},
  57        {0x6081, 0x0026}, {0x6000, 0x0000}, {0x6000, 0x0045}, {0x6000, 0x0010},
  58        {0x6000, 0x005c}, {0x6000, 0x0063}, {0x6000, 0x007c}, {0x6070, 0x0061},
  59        {0x6080, 0x0062}, {0x6080, 0x0020}, {0x6030, 0x0028}, {0x6000, 0x006c},
  60        {0x6000, 0x006e}, {0x6002, 0x0070}, {0x6094, 0x0071}, {0x60c1, 0x0073},
  61        {0x6034, 0x003d}, {0x6057, 0x005a}, {0x60bb, 0x004f}, {0x609c, 0x0050},
  62        {0x6080, 0x006d}, {0x6002, 0x0039}, {0x6033, 0x003a}, {0x60f1, 0x003b},
  63        {0x6031, 0x003c}, {0x6000, 0x00ff}, {0x6014, 0x00e0}, {0x60ff, 0x0076},
  64        {0x60a0, 0x0033}, {0x6020, 0x0042}, {0x6018, 0x0043}, {0x6000, 0x004c},
  65        {0x60d0, 0x0087}, {0x600f, 0x0088}, {0x6003, 0x00d7}, {0x6010, 0x00d9},
  66        {0x6005, 0x00da}, {0x6082, 0x00d3}, {0x60c0, 0x00f9}, {0x6006, 0x0044},
  67        {0x6007, 0x00d1}, {0x6002, 0x00d2}, {0x6000, 0x00d2}, {0x6011, 0x00d8},
  68        {0x6008, 0x00c8}, {0x6080, 0x00c9}, {0x6008, 0x007c}, {0x6020, 0x007d},
  69        {0x6020, 0x007d}, {0x6000, 0x0090}, {0x600e, 0x0091}, {0x601a, 0x0091},
  70        {0x6031, 0x0091}, {0x605a, 0x0091}, {0x6069, 0x0091}, {0x6075, 0x0091},
  71        {0x607e, 0x0091}, {0x6088, 0x0091}, {0x608f, 0x0091}, {0x6096, 0x0091},
  72        {0x60a3, 0x0091}, {0x60af, 0x0091}, {0x60c4, 0x0091}, {0x60d7, 0x0091},
  73        {0x60e8, 0x0091}, {0x6020, 0x0091}, {0x6000, 0x0092}, {0x6006, 0x0093},
  74        {0x60e3, 0x0093}, {0x6005, 0x0093}, {0x6005, 0x0093}, {0x6000, 0x0093},
  75        {0x6004, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093},
  76        {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093}, {0x6000, 0x0093},
  77        {0x6000, 0x0096}, {0x6008, 0x0097}, {0x6019, 0x0097}, {0x6002, 0x0097},
  78        {0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097}, {0x6028, 0x0097},
  79        {0x6026, 0x0097}, {0x6002, 0x0097}, {0x6098, 0x0097}, {0x6080, 0x0097},
  80        {0x6000, 0x0097}, {0x6000, 0x0097}, {0x60ed, 0x00c3}, {0x609a, 0x00c4},
  81        {0x6000, 0x00a4}, {0x6011, 0x00c5}, {0x6051, 0x00c6}, {0x6010, 0x00c7},
  82        {0x6066, 0x00b6}, {0x60a5, 0x00b8}, {0x6064, 0x00b7}, {0x607c, 0x00b9},
  83        {0x60af, 0x00b3}, {0x6097, 0x00b4}, {0x60ff, 0x00b5}, {0x60c5, 0x00b0},
  84        {0x6094, 0x00b1}, {0x600f, 0x00b2}, {0x605c, 0x00c4}, {0x6000, 0x00a8},
  85        {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x601d, 0x0086}, {0x6000, 0x0050},
  86        {0x6090, 0x0051}, {0x6018, 0x0052}, {0x6000, 0x0053}, {0x6000, 0x0054},
  87        {0x6088, 0x0055}, {0x6000, 0x0057}, {0x6090, 0x005a}, {0x6018, 0x005b},
  88        {0x6005, 0x005c}, {0x60ed, 0x00c3}, {0x6000, 0x007f}, {0x6005, 0x00da},
  89        {0x601f, 0x00e5}, {0x6067, 0x00e1}, {0x6000, 0x00e0}, {0x60ff, 0x00dd},
  90        {0x6000, 0x0005}, {0x6001, 0x00ff}, {0x6000, 0x0000}, {0x6000, 0x0045},
  91        {0x6000, 0x0010},
  92};
  93
  94static struct validx tbl_sensor_settings_common1[] = {
  95        {0x0041, 0x0000}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d},
  96        {0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0001, 0x00c1}, {0x0041, 0x00c2},
  97        {0x0004, 0x00d8}, {0x0012, 0x0004}, {0x0000, 0x0058}, {0x0041, 0x0000},
  98        {50, 0xffff},
  99        {0x0061, 0x0000},
 100        {0xffff, 0xffff},
 101        {0x6000, 0x00ff}, {0x6000, 0x007c}, {0x6007, 0x007d},
 102        {30, 0xffff},
 103        {0x0040, 0x0000},
 104};
 105
 106static struct validx tbl_sensor_settings_common2[] = {
 107        {0x6001, 0x00ff}, {0x6038, 0x000c},
 108        {10, 0xffff},
 109        {0x6000, 0x0011},
 110};
 111
 112static struct validx tbl_640[] = {
 113        {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1},
 114        {0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
 115        {0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017},
 116        {0x6075, 0x0018}, {0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032},
 117        {0x60bb, 0x004f}, {0x6057, 0x005a}, {0x609c, 0x0050}, {0x6080, 0x006d},
 118        {0x6092, 0x0026}, {0x60ff, 0x0020}, {0x6000, 0x0027}, {0x6000, 0x00ff},
 119        {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c}, {0x603d, 0x0086},
 120        {0x6089, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052}, {0x6000, 0x0053},
 121        {0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057}, {0x60a0, 0x005a},
 122        {0x6078, 0x005b}, {0x6000, 0x005c}, {0x6004, 0x00d3}, {0x6000, 0x00e0},
 123        {0x60ff, 0x00dd}, {0x60a1, 0x005a},
 124};
 125
 126static struct validx tbl_800[] = {
 127        {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0}, {0x6067, 0x00e1},
 128        {0x6004, 0x00da}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
 129        {0x6001, 0x00ff}, {0x6040, 0x0012}, {0x6000, 0x0011}, {0x6011, 0x0017},
 130        {0x6043, 0x0018}, {0x6000, 0x0019}, {0x604b, 0x001a}, {0x6009, 0x0032},
 131        {0x60ca, 0x004f}, {0x60a8, 0x0050}, {0x6000, 0x006d}, {0x6038, 0x003d},
 132        {0x60c8, 0x0035}, {0x6000, 0x0022}, {0x6092, 0x0026}, {0x60ff, 0x0020},
 133        {0x6000, 0x0027}, {0x6000, 0x00ff}, {0x6064, 0x00c0}, {0x604b, 0x00c1},
 134        {0x6000, 0x008c}, {0x601d, 0x0086}, {0x6082, 0x00d3}, {0x6000, 0x00e0},
 135        {0x60ff, 0x00dd}, {0x6020, 0x008c}, {0x6001, 0x00ff}, {0x6044, 0x0018},
 136};
 137
 138static struct validx tbl_big1[] = {
 139        {0x0002, 0x00c1}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
 140        {0x6001, 0x00ff}, {0x6000, 0x0012}, {0x6000, 0x0000}, {0x6000, 0x0045},
 141        {0x6000, 0x0010}, {0x6000, 0x0011}, {0x6011, 0x0017}, {0x6075, 0x0018},
 142        {0x6001, 0x0019}, {0x6097, 0x001a}, {0x6036, 0x0032}, {0x60bb, 0x004f},
 143        {0x609c, 0x0050}, {0x6057, 0x005a}, {0x6080, 0x006d}, {0x6043, 0x000f},
 144        {0x608f, 0x0003}, {0x6005, 0x007c}, {0x6081, 0x0026}, {0x6000, 0x00ff},
 145        {0x60c8, 0x00c0}, {0x6096, 0x00c1}, {0x6000, 0x008c},
 146};
 147
 148static struct validx tbl_big2[] = {
 149        {0x603d, 0x0086}, {0x6000, 0x0050}, {0x6090, 0x0051}, {0x602c, 0x0052},
 150        {0x6000, 0x0053}, {0x6000, 0x0054}, {0x6088, 0x0055}, {0x6000, 0x0057},
 151        {0x6040, 0x005a}, {0x60f0, 0x005b}, {0x6001, 0x005c}, {0x6082, 0x00d3},
 152        {0x6000, 0x008e},
 153};
 154
 155static struct validx tbl_big3[] = {
 156        {0x6004, 0x00da}, {0x6000, 0x00e0}, {0x6067, 0x00e1}, {0x60ff, 0x00dd},
 157        {0x6001, 0x00ff}, {0x6000, 0x00ff}, {0x60f1, 0x00dd}, {0x6004, 0x00e0},
 158        {0x6001, 0x00ff}, {0x6000, 0x0011}, {0x6000, 0x00ff}, {0x6010, 0x00c7},
 159        {0x6000, 0x0092}, {0x6006, 0x0093}, {0x60e3, 0x0093}, {0x6005, 0x0093},
 160        {0x6005, 0x0093}, {0x60ed, 0x00c3}, {0x6000, 0x00a4}, {0x60d0, 0x0087},
 161        {0x6003, 0x0096}, {0x600c, 0x0097}, {0x6024, 0x0097}, {0x6030, 0x0097},
 162        {0x6028, 0x0097}, {0x6026, 0x0097}, {0x6002, 0x0097}, {0x6001, 0x00ff},
 163        {0x6043, 0x000f}, {0x608f, 0x0003}, {0x6000, 0x002d}, {0x6000, 0x002e},
 164        {0x600a, 0x0022}, {0x6002, 0x0070}, {0x6008, 0x0014}, {0x6048, 0x0014},
 165        {0x6000, 0x00ff}, {0x6000, 0x00e0}, {0x60ff, 0x00dd},
 166};
 167
 168static struct validx tbl_post_unset_alt[] = {
 169        {0x006a, 0x000d}, {0x6001, 0x00ff}, {0x6081, 0x0026}, {0x6000, 0x0000},
 170        {0x6000, 0x0045}, {0x6000, 0x0010}, {0x6068, 0x000d},
 171        {50, 0xffff},
 172        {0x0021, 0x0000},
 173};
 174
 175static int  ov2640_init_at_startup(struct gspca_dev *gspca_dev);
 176static int  ov2640_configure_alt(struct gspca_dev *gspca_dev);
 177static int  ov2640_init_pre_alt(struct gspca_dev *gspca_dev);
 178static int  ov2640_init_post_alt(struct gspca_dev *gspca_dev);
 179static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev);
 180static int  ov2640_camera_settings(struct gspca_dev *gspca_dev);
 181/*==========================================================================*/
 182
 183void ov2640_init_settings(struct gspca_dev *gspca_dev)
 184{
 185        struct sd *sd = (struct sd *) gspca_dev;
 186
 187        sd->vcur.backlight  =  32;
 188        sd->vcur.brightness =   0;
 189        sd->vcur.sharpness  =   6;
 190        sd->vcur.contrast   =   0;
 191        sd->vcur.gamma      =  32;
 192        sd->vcur.hue        =   0;
 193        sd->vcur.saturation = 128;
 194        sd->vcur.whitebal   =  64;
 195        sd->vcur.mirror     =   0;
 196        sd->vcur.flip       =   0;
 197
 198        sd->vmax.backlight  =  64;
 199        sd->vmax.brightness = 255;
 200        sd->vmax.sharpness  =  31;
 201        sd->vmax.contrast   = 255;
 202        sd->vmax.gamma      =  64;
 203        sd->vmax.hue        = 254 + 2;
 204        sd->vmax.saturation = 255;
 205        sd->vmax.whitebal   = 128;
 206        sd->vmax.mirror     = 1;
 207        sd->vmax.flip       = 1;
 208        sd->vmax.AC50Hz     = 0;
 209
 210        sd->dev_camera_settings = ov2640_camera_settings;
 211        sd->dev_init_at_startup = ov2640_init_at_startup;
 212        sd->dev_configure_alt   = ov2640_configure_alt;
 213        sd->dev_init_pre_alt    = ov2640_init_pre_alt;
 214        sd->dev_post_unset_alt  = ov2640_post_unset_alt;
 215}
 216
 217/*==========================================================================*/
 218
 219static void common(struct gspca_dev *gspca_dev)
 220{
 221        fetch_validx(gspca_dev, tbl_common, ARRAY_SIZE(tbl_common));
 222}
 223
 224static int ov2640_init_at_startup(struct gspca_dev *gspca_dev)
 225{
 226        fetch_validx(gspca_dev, tbl_init_at_startup,
 227                        ARRAY_SIZE(tbl_init_at_startup));
 228
 229        ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_init1);
 230
 231        common(gspca_dev);
 232
 233        ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0006, 1, c61);
 234
 235        ctrl_out(gspca_dev, 0x40, 1, 0x00ef, 0x0006, 0, NULL);
 236
 237        ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c51);
 238
 239        ctrl_out(gspca_dev, 0x40, 1, 0x0051, 0x0000, 0, NULL);
 240/*      ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */
 241
 242        return 0;
 243}
 244
 245static int ov2640_init_pre_alt(struct gspca_dev *gspca_dev)
 246{
 247        struct sd *sd = (struct sd *) gspca_dev;
 248
 249        sd->mirrorMask = 0;
 250
 251        sd->vold.backlight  = -1;
 252        sd->vold.brightness = -1;
 253        sd->vold.sharpness  = -1;
 254        sd->vold.contrast   = -1;
 255        sd->vold.saturation = -1;
 256        sd->vold.gamma    = -1;
 257        sd->vold.hue      = -1;
 258        sd->vold.whitebal = -1;
 259        sd->vold.mirror = -1;
 260        sd->vold.flip   = -1;
 261
 262        ov2640_init_post_alt(gspca_dev);
 263
 264        return 0;
 265}
 266
 267static int ov2640_init_post_alt(struct gspca_dev *gspca_dev)
 268{
 269        s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
 270        s32 n; /* reserved for FETCH functions */
 271
 272        ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
 273
 274        n = fetch_validx(gspca_dev, tbl_sensor_settings_common1,
 275                        ARRAY_SIZE(tbl_sensor_settings_common1));
 276        ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_post);
 277        common(gspca_dev);
 278        keep_on_fetching_validx(gspca_dev, tbl_sensor_settings_common1,
 279                                ARRAY_SIZE(tbl_sensor_settings_common1), n);
 280
 281        switch (reso) {
 282        case IMAGE_640:
 283                n = fetch_validx(gspca_dev, tbl_640, ARRAY_SIZE(tbl_640));
 284                ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_640);
 285                break;
 286
 287        case IMAGE_800:
 288                n = fetch_validx(gspca_dev, tbl_800, ARRAY_SIZE(tbl_800));
 289                ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200, 12, dat_800);
 290                break;
 291
 292        case IMAGE_1600:
 293        case IMAGE_1280:
 294                n = fetch_validx(gspca_dev, tbl_big1, ARRAY_SIZE(tbl_big1));
 295
 296                if (reso == IMAGE_1280) {
 297                        n = fetch_validx(gspca_dev, tbl_big2,
 298                                        ARRAY_SIZE(tbl_big2));
 299                } else {
 300                        ctrl_out(gspca_dev, 0x40, 1, 0x601d, 0x0086, 0, NULL);
 301                        ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00d7, 0, NULL);
 302                        ctrl_out(gspca_dev, 0x40, 1, 0x6082, 0x00d3, 0, NULL);
 303                }
 304
 305                n = fetch_validx(gspca_dev, tbl_big3, ARRAY_SIZE(tbl_big3));
 306
 307                if (reso == IMAGE_1280) {
 308                        ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
 309                        ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
 310                                        12, dat_1280);
 311                } else {
 312                        ctrl_out(gspca_dev, 0x40, 1, 0x6020, 0x008c, 0, NULL);
 313                        ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
 314                        ctrl_out(gspca_dev, 0x40, 1, 0x6076, 0x0018, 0, NULL);
 315                        ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
 316                                        12, dat_1600);
 317                }
 318                break;
 319        }
 320
 321        n = fetch_validx(gspca_dev, tbl_sensor_settings_common2,
 322                        ARRAY_SIZE(tbl_sensor_settings_common2));
 323
 324        ov2640_camera_settings(gspca_dev);
 325
 326        return 0;
 327}
 328
 329static int ov2640_configure_alt(struct gspca_dev *gspca_dev)
 330{
 331        s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
 332
 333        switch (reso) {
 334        case IMAGE_640:
 335                gspca_dev->alt = 3 + 1;
 336                break;
 337
 338        case IMAGE_800:
 339        case IMAGE_1280:
 340        case IMAGE_1600:
 341                gspca_dev->alt = 1 + 1;
 342                break;
 343        }
 344        return 0;
 345}
 346
 347static int ov2640_camera_settings(struct gspca_dev *gspca_dev)
 348{
 349        struct sd *sd = (struct sd *) gspca_dev;
 350
 351        s32 backlight = sd->vcur.backlight;
 352        s32 bright = sd->vcur.brightness;
 353        s32 sharp  = sd->vcur.sharpness;
 354        s32 gam    = sd->vcur.gamma;
 355        s32 cntr   = sd->vcur.contrast;
 356        s32 sat    = sd->vcur.saturation;
 357        s32 hue    = sd->vcur.hue;
 358        s32 wbal   = sd->vcur.whitebal;
 359        s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) == 0);
 360        s32 flip   = (((sd->vcur.flip   > 0) ^ sd->mirrorMask) == 0);
 361
 362        if (backlight != sd->vold.backlight) {
 363                /* No sd->vold.backlight=backlight; (to be done again later) */
 364                if (backlight < 0 || backlight > sd->vmax.backlight)
 365                        backlight = 0;
 366
 367                ctrl_out(gspca_dev, 0x40, 1, 0x6001                 , 0x00ff,
 368                                0, NULL);
 369                ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight     , 0x0024,
 370                                0, NULL);
 371                ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight - 10, 0x0025,
 372                                0, NULL);
 373        }
 374
 375        if (bright != sd->vold.brightness) {
 376                sd->vold.brightness = bright;
 377                if (bright < 0 || bright > sd->vmax.brightness)
 378                        bright = 0;
 379
 380                ctrl_out(gspca_dev, 0x40, 1, 0x6000         , 0x00ff, 0, NULL);
 381                ctrl_out(gspca_dev, 0x40, 1, 0x6009         , 0x007c, 0, NULL);
 382                ctrl_out(gspca_dev, 0x40, 1, 0x6000 + bright, 0x007d, 0, NULL);
 383        }
 384
 385        if (wbal != sd->vold.whitebal) {
 386                sd->vold.whitebal = wbal;
 387                if (wbal < 0 || wbal > sd->vmax.whitebal)
 388                        wbal = 0;
 389
 390                ctrl_out(gspca_dev, 0x40, 1, 0x6000       , 0x00ff, 0, NULL);
 391                ctrl_out(gspca_dev, 0x40, 1, 0x6003       , 0x007c, 0, NULL);
 392                ctrl_out(gspca_dev, 0x40, 1, 0x6000 + wbal, 0x007d, 0, NULL);
 393        }
 394
 395        if (cntr != sd->vold.contrast) {
 396                sd->vold.contrast = cntr;
 397                if (cntr < 0 || cntr > sd->vmax.contrast)
 398                        cntr = 0;
 399
 400                ctrl_out(gspca_dev, 0x40, 1, 0x6000       , 0x00ff, 0, NULL);
 401                ctrl_out(gspca_dev, 0x40, 1, 0x6007       , 0x007c, 0, NULL);
 402                ctrl_out(gspca_dev, 0x40, 1, 0x6000 + cntr, 0x007d, 0, NULL);
 403        }
 404
 405        if (sat != sd->vold.saturation) {
 406                sd->vold.saturation = sat;
 407                if (sat < 0 || sat > sd->vmax.saturation)
 408                        sat = 0;
 409
 410                ctrl_out(gspca_dev, 0x40, 1, 0x6000      , 0x00ff, 0, NULL);
 411                ctrl_out(gspca_dev, 0x40, 1, 0x6001      , 0x007c, 0, NULL);
 412                ctrl_out(gspca_dev, 0x40, 1, 0x6000 + sat, 0x007d, 0, NULL);
 413        }
 414
 415        if (sharp != sd->vold.sharpness) {
 416                sd->vold.sharpness = sharp;
 417                if (sharp < 0 || sharp > sd->vmax.sharpness)
 418                        sharp = 0;
 419
 420                ctrl_out(gspca_dev, 0x40, 1, 0x6000        , 0x00ff, 0, NULL);
 421                ctrl_out(gspca_dev, 0x40, 1, 0x6001        , 0x0092, 0, NULL);
 422                ctrl_out(gspca_dev, 0x40, 1, 0x60c0 + sharp, 0x0093, 0, NULL);
 423        }
 424
 425        if (hue != sd->vold.hue) {
 426                sd->vold.hue = hue;
 427                if (hue < 0 || hue > sd->vmax.hue)
 428                        hue = 0;
 429
 430                ctrl_out(gspca_dev, 0x40, 1, 0x6000     , 0x00ff, 0, NULL);
 431                ctrl_out(gspca_dev, 0x40, 1, 0x6002     , 0x007c, 0, NULL);
 432                ctrl_out(gspca_dev, 0x40, 1, 0x6000 + hue * (hue < 255), 0x007d,
 433                                0, NULL);
 434                if (hue >= 255)
 435                        sd->swapRB = 1;
 436                else
 437                        sd->swapRB = 0;
 438        }
 439
 440        if (gam != sd->vold.gamma) {
 441                sd->vold.gamma = gam;
 442                if (gam < 0 || gam > sd->vmax.gamma)
 443                        gam = 0;
 444
 445                ctrl_out(gspca_dev, 0x40, 1, 0x6000      , 0x00ff, 0, NULL);
 446                ctrl_out(gspca_dev, 0x40, 1, 0x6008      , 0x007c, 0, NULL);
 447                ctrl_out(gspca_dev, 0x40, 1, 0x6000 + gam, 0x007d, 0, NULL);
 448        }
 449
 450        if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
 451                sd->vold.mirror = mirror;
 452                sd->vold.flip   = flip;
 453
 454                mirror = 0x80 * mirror;
 455                ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
 456                ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x8004, 0, NULL);
 457                ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, c28);
 458                ctrl_out(gspca_dev, 0x40, 1, 0x6028 + mirror, 0x0004, 0, NULL);
 459
 460                flip = 0x50 * flip + mirror;
 461                ctrl_out(gspca_dev, 0x40, 1, 0x6001, 0x00ff, 0, NULL);
 462                ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x8004, 0, NULL);
 463                ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x8004, 1, ca8);
 464                ctrl_out(gspca_dev, 0x40, 1, 0x6028 + flip, 0x0004, 0, NULL);
 465
 466                ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, c50);
 467        }
 468
 469        if (backlight != sd->vold.backlight) {
 470                sd->vold.backlight = backlight;
 471
 472                ctrl_out(gspca_dev, 0x40, 1, 0x6001                 , 0x00ff,
 473                                0, NULL);
 474                ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight     , 0x0024,
 475                                0, NULL);
 476                ctrl_out(gspca_dev, 0x40, 1, 0x601e + backlight - 10, 0x0025,
 477                                0, NULL);
 478        }
 479
 480        return 0;
 481}
 482
 483static void ov2640_post_unset_alt(struct gspca_dev *gspca_dev)
 484{
 485        ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
 486        msleep(20);
 487        fetch_validx(gspca_dev, tbl_post_unset_alt,
 488                        ARRAY_SIZE(tbl_post_unset_alt));
 489}
 490