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