root/drivers/media/usb/gspca/mr97310a.c
// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Mars MR97310A library
 *
 * The original mr97310a driver, which supported the Aiptek Pencam VGA+, is
 * Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com>
 *
 * Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+
 * and for the routines for detecting and classifying these various cameras,
 * is Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
 *
 * Support for the control settings for the CIF cameras is
 * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com> and
 * Thomas Kaiser <thomas@kaiser-linux.li>
 *
 * Support for the control settings for the VGA cameras is
 * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
 *
 * Several previously unsupported cameras are owned and have been tested by
 * Hans de Goede <hdegoede@redhat.com> and
 * Thomas Kaiser <thomas@kaiser-linux.li> and
 * Theodore Kilgore <kilgota@auburn.edu> and
 * Edmond Rodriguez <erodrig_97@yahoo.com> and
 * Aurelien Jacobs <aurel@gnuage.org>
 *
 * The MR97311A support in gspca/mars.c has been helpful in understanding some
 * of the registers in these cameras.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#define MODULE_NAME "mr97310a"

#include "gspca.h"

#define CAM_TYPE_CIF                    0
#define CAM_TYPE_VGA                    1

#define MR97310A_BRIGHTNESS_DEFAULT     0

#define MR97310A_EXPOSURE_MIN           0
#define MR97310A_EXPOSURE_MAX           4095
#define MR97310A_EXPOSURE_DEFAULT       1000

#define MR97310A_GAIN_MIN               0
#define MR97310A_GAIN_MAX               31
#define MR97310A_GAIN_DEFAULT           25

#define MR97310A_CONTRAST_MIN           0
#define MR97310A_CONTRAST_MAX           31
#define MR97310A_CONTRAST_DEFAULT       23

#define MR97310A_CS_GAIN_MIN            0
#define MR97310A_CS_GAIN_MAX            0x7ff
#define MR97310A_CS_GAIN_DEFAULT        0x110

#define MR97310A_CID_CLOCKDIV (V4L2_CTRL_CLASS_USER + 0x1000)
#define MR97310A_MIN_CLOCKDIV_MIN       3
#define MR97310A_MIN_CLOCKDIV_MAX       8
#define MR97310A_MIN_CLOCKDIV_DEFAULT   3

MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>,Theodore Kilgore <kilgota@auburn.edu>");
MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver");
MODULE_LICENSE("GPL");

/* global parameters */
static int force_sensor_type = -1;
module_param(force_sensor_type, int, 0644);
MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)");

/* specific webcam descriptor */
struct sd {
        struct gspca_dev gspca_dev;  /* !! must be the first item */
        struct { /* exposure/min_clockdiv control cluster */
                struct v4l2_ctrl *exposure;
                struct v4l2_ctrl *min_clockdiv;
        };
        u8 sof_read;
        u8 cam_type;    /* 0 is CIF and 1 is VGA */
        u8 sensor_type; /* We use 0 and 1 here, too. */
        u8 do_lcd_stop;
        u8 adj_colors;
};

struct sensor_w_data {
        u8 reg;
        u8 flags;
        u8 data[16];
        int len;
};

static void sd_stopN(struct gspca_dev *gspca_dev);

static const struct v4l2_pix_format vga_mode[] = {
        {160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
                .bytesperline = 160,
                .sizeimage = 160 * 120,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 4},
        {176, 144, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
                .bytesperline = 176,
                .sizeimage = 176 * 144,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 3},
        {320, 240, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
                .bytesperline = 320,
                .sizeimage = 320 * 240,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 2},
        {352, 288, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
                .bytesperline = 352,
                .sizeimage = 352 * 288,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 1},
        {640, 480, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE,
                .bytesperline = 640,
                .sizeimage = 640 * 480,
                .colorspace = V4L2_COLORSPACE_SRGB,
                .priv = 0},
};

/* the bytes to write are in gspca_dev->usb_buf */
static int mr_write(struct gspca_dev *gspca_dev, int len)
{
        int rc;

        rc = usb_bulk_msg(gspca_dev->dev,
                          usb_sndbulkpipe(gspca_dev->dev, 4),
                          gspca_dev->usb_buf, len, NULL, 500);
        if (rc < 0)
                pr_err("reg write [%02x] error %d\n",
                       gspca_dev->usb_buf[0], rc);
        return rc;
}

/* the bytes are read into gspca_dev->usb_buf */
static int mr_read(struct gspca_dev *gspca_dev, int len)
{
        int rc;

        rc = usb_bulk_msg(gspca_dev->dev,
                          usb_rcvbulkpipe(gspca_dev->dev, 3),
                          gspca_dev->usb_buf, len, NULL, 500);
        if (rc < 0)
                pr_err("reg read [%02x] error %d\n",
                       gspca_dev->usb_buf[0], rc);
        return rc;
}

static int sensor_write_reg(struct gspca_dev *gspca_dev, u8 reg, u8 flags,
        const u8 *data, int len)
{
        gspca_dev->usb_buf[0] = 0x1f;
        gspca_dev->usb_buf[1] = flags;
        gspca_dev->usb_buf[2] = reg;
        memcpy(gspca_dev->usb_buf + 3, data, len);

        return mr_write(gspca_dev, len + 3);
}

static int sensor_write_regs(struct gspca_dev *gspca_dev,
        const struct sensor_w_data *data, int len)
{
        int i, rc;

        for (i = 0; i < len; i++) {
                rc = sensor_write_reg(gspca_dev, data[i].reg, data[i].flags,
                                          data[i].data, data[i].len);
                if (rc < 0)
                        return rc;
        }

        return 0;
}

static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data)
{
        struct sd *sd = (struct sd *) gspca_dev;
        u8 buf, confirm_reg;
        int rc;

        buf = data;
        if (sd->cam_type == CAM_TYPE_CIF) {
                rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1);
                confirm_reg = sd->sensor_type ? 0x13 : 0x11;
        } else {
                rc = sensor_write_reg(gspca_dev, reg, 0x00, &buf, 1);
                confirm_reg = 0x11;
        }
        if (rc < 0)
                return rc;

        buf = 0x01;
        rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1);
        if (rc < 0)
                return rc;

        return 0;
}

static int cam_get_response16(struct gspca_dev *gspca_dev, u8 reg, int verbose)
{
        int err_code;

        gspca_dev->usb_buf[0] = reg;
        err_code = mr_write(gspca_dev, 1);
        if (err_code < 0)
                return err_code;

        err_code = mr_read(gspca_dev, 16);
        if (err_code < 0)
                return err_code;

        if (verbose)
                gspca_dbg(gspca_dev, D_PROBE, "Register: %02x reads %02x%02x%02x\n",
                          reg,
                          gspca_dev->usb_buf[0],
                          gspca_dev->usb_buf[1],
                          gspca_dev->usb_buf[2]);

        return 0;
}

static int zero_the_pointer(struct gspca_dev *gspca_dev)
{
        __u8 *data = gspca_dev->usb_buf;
        int err_code;
        u8 status = 0;
        int tries = 0;

        err_code = cam_get_response16(gspca_dev, 0x21, 0);
        if (err_code < 0)
                return err_code;

        data[0] = 0x19;
        data[1] = 0x51;
        err_code = mr_write(gspca_dev, 2);
        if (err_code < 0)
                return err_code;

        err_code = cam_get_response16(gspca_dev, 0x21, 0);
        if (err_code < 0)
                return err_code;

        data[0] = 0x19;
        data[1] = 0xba;
        err_code = mr_write(gspca_dev, 2);
        if (err_code < 0)
                return err_code;

        err_code = cam_get_response16(gspca_dev, 0x21, 0);
        if (err_code < 0)
                return err_code;

        data[0] = 0x19;
        data[1] = 0x00;
        err_code = mr_write(gspca_dev, 2);
        if (err_code < 0)
                return err_code;

        err_code = cam_get_response16(gspca_dev, 0x21, 0);
        if (err_code < 0)
                return err_code;

        data[0] = 0x19;
        data[1] = 0x00;
        err_code = mr_write(gspca_dev, 2);
        if (err_code < 0)
                return err_code;

        while (status != 0x0a && tries < 256) {
                err_code = cam_get_response16(gspca_dev, 0x21, 0);
                status = data[0];
                tries++;
                if (err_code < 0)
                        return err_code;
        }
        if (status != 0x0a)
                gspca_err(gspca_dev, "status is %02x\n", status);

        tries = 0;
        while (tries < 4) {
                data[0] = 0x19;
                data[1] = 0x00;
                err_code = mr_write(gspca_dev, 2);
                if (err_code < 0)
                        return err_code;

                err_code = cam_get_response16(gspca_dev, 0x21, 0);
                tries++;
                if (err_code < 0)
                        return err_code;
        }

        data[0] = 0x19;
        err_code = mr_write(gspca_dev, 1);
        if (err_code < 0)
                return err_code;

        err_code = mr_read(gspca_dev, 16);
        if (err_code < 0)
                return err_code;

        return 0;
}

static int stream_start(struct gspca_dev *gspca_dev)
{
        gspca_dev->usb_buf[0] = 0x01;
        gspca_dev->usb_buf[1] = 0x01;
        return mr_write(gspca_dev, 2);
}

static void stream_stop(struct gspca_dev *gspca_dev)
{
        gspca_dev->usb_buf[0] = 0x01;
        gspca_dev->usb_buf[1] = 0x00;
        if (mr_write(gspca_dev, 2) < 0)
                gspca_err(gspca_dev, "Stream Stop failed\n");
}

static void lcd_stop(struct gspca_dev *gspca_dev)
{
        gspca_dev->usb_buf[0] = 0x19;
        gspca_dev->usb_buf[1] = 0x54;
        if (mr_write(gspca_dev, 2) < 0)
                gspca_err(gspca_dev, "LCD Stop failed\n");
}

static int isoc_enable(struct gspca_dev *gspca_dev)
{
        gspca_dev->usb_buf[0] = 0x00;
        gspca_dev->usb_buf[1] = 0x4d;  /* ISOC transferring enable... */
        return mr_write(gspca_dev, 2);
}

/* This function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
                     const struct usb_device_id *id)
{
        struct sd *sd = (struct sd *) gspca_dev;
        struct cam *cam;
        int err_code;

        cam = &gspca_dev->cam;
        cam->cam_mode = vga_mode;
        cam->nmodes = ARRAY_SIZE(vga_mode);
        sd->do_lcd_stop = 0;

        /* Several of the supported CIF cameras share the same USB ID but
         * require different initializations and different control settings.
         * The same is true of the VGA cameras. Therefore, we are forced
         * to start the initialization process in order to determine which
         * camera is present. Some of the supported cameras require the
         * memory pointer to be set to 0 as the very first item of business
         * or else they will not stream. So we do that immediately.
         */
        err_code = zero_the_pointer(gspca_dev);
        if (err_code < 0)
                return err_code;

        err_code = stream_start(gspca_dev);
        if (err_code < 0)
                return err_code;

        /* Now, the query for sensor type. */
        err_code = cam_get_response16(gspca_dev, 0x07, 1);
        if (err_code < 0)
                return err_code;

        if (id->idProduct == 0x0110 || id->idProduct == 0x010e) {
                sd->cam_type = CAM_TYPE_CIF;
                cam->nmodes--;
                /*
                 * All but one of the known CIF cameras share the same USB ID,
                 * but two different init routines are in use, and the control
                 * settings are different, too. We need to detect which camera
                 * of the two known varieties is connected!
                 *
                 * A list of known CIF cameras follows. They all report either
                 * 0200 for type 0 or 0300 for type 1.
                 * If you have another to report, please do
                 *
                 * Name         sd->sensor_type         reported by
                 *
                 * Sakar 56379 Spy-shot 0               T. Kilgore
                 * Innovage             0               T. Kilgore
                 * Vivitar Mini         0               H. De Goede
                 * Vivitar Mini         0               E. Rodriguez
                 * Vivitar Mini         1               T. Kilgore
                 * Elta-Media 8212dc    1               T. Kaiser
                 * Philips dig. keych.  1               T. Kilgore
                 * Trust Spyc@m 100     1               A. Jacobs
                 */
                switch (gspca_dev->usb_buf[0]) {
                case 2:
                        sd->sensor_type = 0;
                        break;
                case 3:
                        sd->sensor_type = 1;
                        break;
                default:
                        pr_err("Unknown CIF Sensor id : %02x\n",
                               gspca_dev->usb_buf[1]);
                        return -ENODEV;
                }
                gspca_dbg(gspca_dev, D_PROBE, "MR97310A CIF camera detected, sensor: %d\n",
                          sd->sensor_type);
        } else {
                sd->cam_type = CAM_TYPE_VGA;

                /*
                 * Here is a table of the responses to the query for sensor
                 * type, from the known MR97310A VGA cameras. Six different
                 * cameras of which five share the same USB ID.
                 *
                 * Name                 gspca_dev->usb_buf[]    sd->sensor_type
                 *                              sd->do_lcd_stop
                 * Aiptek Pencam VGA+   0300            0               1
                 * ION digital          0300            0               1
                 * Argus DC-1620        0450            1               0
                 * Argus QuickClix      0420            1               1
                 * Sakar 77379 Digital  0350            0               1
                 * Sakar 1638x CyberPix 0120            0               2
                 *
                 * Based upon these results, we assume default settings
                 * and then correct as necessary, as follows.
                 *
                 */

                sd->sensor_type = 1;
                sd->do_lcd_stop = 0;
                sd->adj_colors = 0;
                if (gspca_dev->usb_buf[0] == 0x01) {
                        sd->sensor_type = 2;
                } else if ((gspca_dev->usb_buf[0] != 0x03) &&
                                        (gspca_dev->usb_buf[0] != 0x04)) {
                        pr_err("Unknown VGA Sensor id Byte 0: %02x\n",
                               gspca_dev->usb_buf[0]);
                        pr_err("Defaults assumed, may not work\n");
                        pr_err("Please report this\n");
                }
                /* Sakar Digital color needs to be adjusted. */
                if ((gspca_dev->usb_buf[0] == 0x03) &&
                                        (gspca_dev->usb_buf[1] == 0x50))
                        sd->adj_colors = 1;
                if (gspca_dev->usb_buf[0] == 0x04) {
                        sd->do_lcd_stop = 1;
                        switch (gspca_dev->usb_buf[1]) {
                        case 0x50:
                                sd->sensor_type = 0;
                                gspca_dbg(gspca_dev, D_PROBE, "sensor_type corrected to 0\n");
                                break;
                        case 0x20:
                                /* Nothing to do here. */
                                break;
                        default:
                                pr_err("Unknown VGA Sensor id Byte 1: %02x\n",
                                       gspca_dev->usb_buf[1]);
                                pr_err("Defaults assumed, may not work\n");
                                pr_err("Please report this\n");
                        }
                }
                gspca_dbg(gspca_dev, D_PROBE, "MR97310A VGA camera detected, sensor: %d\n",
                          sd->sensor_type);
        }
        /* Stop streaming as we've started it only to probe the sensor type. */
        sd_stopN(gspca_dev);

        if (force_sensor_type != -1) {
                sd->sensor_type = !!force_sensor_type;
                gspca_dbg(gspca_dev, D_PROBE, "Forcing sensor type to: %d\n",
                          sd->sensor_type);
        }

        return 0;
}

/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
        return 0;
}

static int start_cif_cam(struct gspca_dev *gspca_dev)
{
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 *data = gspca_dev->usb_buf;
        int err_code;
        static const __u8 startup_string[] = {
                0x00,
                0x0d,
                0x01,
                0x00, /* Hsize/8 for 352 or 320 */
                0x00, /* Vsize/4 for 288 or 240 */
                0x13, /* or 0xbb, depends on sensor */
                0x00, /* Hstart, depends on res. */
                0x00, /* reserved ? */
                0x00, /* Vstart, depends on res. and sensor */
                0x50, /* 0x54 to get 176 or 160 */
                0xc0
        };

        /* Note: Some of the above descriptions guessed from MR97113A driver */

        memcpy(data, startup_string, 11);
        if (sd->sensor_type)
                data[5] = 0xbb;

        switch (gspca_dev->pixfmt.width) {
        case 160:
                data[9] |= 0x04;  /* reg 8, 2:1 scale down from 320 */
                fallthrough;
        case 320:
        default:
                data[3] = 0x28;                    /* reg 2, H size/8 */
                data[4] = 0x3c;                    /* reg 3, V size/4 */
                data[6] = 0x14;                    /* reg 5, H start  */
                data[8] = 0x1a + sd->sensor_type;  /* reg 7, V start  */
                break;
        case 176:
                data[9] |= 0x04;  /* reg 8, 2:1 scale down from 352 */
                fallthrough;
        case 352:
                data[3] = 0x2c;                    /* reg 2, H size/8 */
                data[4] = 0x48;                    /* reg 3, V size/4 */
                data[6] = 0x06;                    /* reg 5, H start  */
                data[8] = 0x06 - sd->sensor_type;  /* reg 7, V start  */
                break;
        }
        err_code = mr_write(gspca_dev, 11);
        if (err_code < 0)
                return err_code;

        if (!sd->sensor_type) {
                static const struct sensor_w_data cif_sensor0_init_data[] = {
                        {0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01,
                                      0x0f, 0x14, 0x0f, 0x10}, 8},
                        {0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5},
                        {0x12, 0x00, {0x07}, 1},
                        {0x1f, 0x00, {0x06}, 1},
                        {0x27, 0x00, {0x04}, 1},
                        {0x29, 0x00, {0x0c}, 1},
                        {0x40, 0x00, {0x40, 0x00, 0x04}, 3},
                        {0x50, 0x00, {0x60}, 1},
                        {0x60, 0x00, {0x06}, 1},
                        {0x6b, 0x00, {0x85, 0x85, 0xc8, 0xc8, 0xc8, 0xc8}, 6},
                        {0x72, 0x00, {0x1e, 0x56}, 2},
                        {0x75, 0x00, {0x58, 0x40, 0xa2, 0x02, 0x31, 0x02,
                                      0x31, 0x80, 0x00}, 9},
                        {0x11, 0x00, {0x01}, 1},
                        {0, 0, {0}, 0}
                };
                err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data,
                                         ARRAY_SIZE(cif_sensor0_init_data));
        } else {        /* sd->sensor_type = 1 */
                static const struct sensor_w_data cif_sensor1_init_data[] = {
                        /* Reg 3,4, 7,8 get set by the controls */
                        {0x02, 0x00, {0x10}, 1},
                        {0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */
                        {0x06, 0x01, {0x00}, 1},
                        {0x09, 0x02, {0x0e}, 1},
                        {0x0a, 0x02, {0x05}, 1},
                        {0x0b, 0x02, {0x05}, 1},
                        {0x0c, 0x02, {0x0f}, 1},
                        {0x0d, 0x02, {0x07}, 1},
                        {0x0e, 0x02, {0x0c}, 1},
                        {0x0f, 0x00, {0x00}, 1},
                        {0x10, 0x00, {0x06}, 1},
                        {0x11, 0x00, {0x07}, 1},
                        {0x12, 0x00, {0x00}, 1},
                        {0x13, 0x00, {0x01}, 1},
                        {0, 0, {0}, 0}
                };
                /* Without this command the cam won't work with USB-UHCI */
                gspca_dev->usb_buf[0] = 0x0a;
                gspca_dev->usb_buf[1] = 0x00;
                err_code = mr_write(gspca_dev, 2);
                if (err_code < 0)
                        return err_code;
                err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data,
                                         ARRAY_SIZE(cif_sensor1_init_data));
        }
        return err_code;
}

static int start_vga_cam(struct gspca_dev *gspca_dev)
{
        struct sd *sd = (struct sd *) gspca_dev;
        __u8 *data = gspca_dev->usb_buf;
        int err_code;
        static const __u8 startup_string[] =
                {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b, 0x00, 0x00,
                 0x00, 0x50, 0xc0};
        /* What some of these mean is explained in start_cif_cam(), above */

        memcpy(data, startup_string, 11);
        if (!sd->sensor_type) {
                data[5]  = 0x00;
                data[10] = 0x91;
        }
        if (sd->sensor_type == 2) {
                data[5]  = 0x00;
                data[10] = 0x18;
        }

        switch (gspca_dev->pixfmt.width) {
        case 160:
                data[9] |= 0x0c;  /* reg 8, 4:1 scale down */
                fallthrough;
        case 320:
                data[9] |= 0x04;  /* reg 8, 2:1 scale down */
                fallthrough;
        case 640:
        default:
                data[3] = 0x50;  /* reg 2, H size/8 */
                data[4] = 0x78;  /* reg 3, V size/4 */
                data[6] = 0x04;  /* reg 5, H start */
                data[8] = 0x03;  /* reg 7, V start */
                if (sd->sensor_type == 2) {
                        data[6] = 2;
                        data[8] = 1;
                }
                if (sd->do_lcd_stop)
                        data[8] = 0x04;  /* Bayer tile shifted */
                break;

        case 176:
                data[9] |= 0x04;  /* reg 8, 2:1 scale down */
                fallthrough;
        case 352:
                data[3] = 0x2c;  /* reg 2, H size */
                data[4] = 0x48;  /* reg 3, V size */
                data[6] = 0x94;  /* reg 5, H start */
                data[8] = 0x63;  /* reg 7, V start */
                if (sd->do_lcd_stop)
                        data[8] = 0x64;  /* Bayer tile shifted */
                break;
        }

        err_code = mr_write(gspca_dev, 11);
        if (err_code < 0)
                return err_code;

        if (!sd->sensor_type) {
                static const struct sensor_w_data vga_sensor0_init_data[] = {
                        {0x01, 0x00, {0x0c, 0x00, 0x04}, 3},
                        {0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4},
                        {0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4},
                        {0x25, 0x00, {0x03, 0xa9, 0x80}, 3},
                        {0x30, 0x00, {0x30, 0x18, 0x10, 0x18}, 4},
                        {0, 0, {0}, 0}
                };
                err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data,
                                         ARRAY_SIZE(vga_sensor0_init_data));
        } else if (sd->sensor_type == 1) {
                static const struct sensor_w_data color_adj[] = {
                        {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
                                /* adjusted blue, green, red gain correct
                                   too much blue from the Sakar Digital */
                                0x05, 0x01, 0x04}, 8}
                };

                static const struct sensor_w_data color_no_adj[] = {
                        {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
                                /* default blue, green, red gain settings */
                                0x07, 0x00, 0x01}, 8}
                };

                static const struct sensor_w_data vga_sensor1_init_data[] = {
                        {0x11, 0x04, {0x01}, 1},
                        {0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01,
                        /* These settings may be better for some cameras */
                        /* {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01, */
                                0x00, 0x0a}, 7},
                        {0x11, 0x04, {0x01}, 1},
                        {0x12, 0x00, {0x00, 0x63, 0x00, 0x70, 0x00, 0x00}, 6},
                        {0x11, 0x04, {0x01}, 1},
                        {0, 0, {0}, 0}
                };

                if (sd->adj_colors)
                        err_code = sensor_write_regs(gspca_dev, color_adj,
                                         ARRAY_SIZE(color_adj));
                else
                        err_code = sensor_write_regs(gspca_dev, color_no_adj,
                                         ARRAY_SIZE(color_no_adj));

                if (err_code < 0)
                        return err_code;

                err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data,
                                         ARRAY_SIZE(vga_sensor1_init_data));
        } else {        /* sensor type == 2 */
                static const struct sensor_w_data vga_sensor2_init_data[] = {

                        {0x01, 0x00, {0x48}, 1},
                        {0x02, 0x00, {0x22}, 1},
                        /* Reg 3 msb and 4 is lsb of the exposure setting*/
                        {0x05, 0x00, {0x10}, 1},
                        {0x06, 0x00, {0x00}, 1},
                        {0x07, 0x00, {0x00}, 1},
                        {0x08, 0x00, {0x00}, 1},
                        {0x09, 0x00, {0x00}, 1},
                        /* The following are used in the gain control
                         * which is BTW completely borked in the OEM driver
                         * The values for each color go from 0 to 0x7ff
                         *{0x0a, 0x00, {0x01}, 1},  green1 gain msb
                         *{0x0b, 0x00, {0x10}, 1},  green1 gain lsb
                         *{0x0c, 0x00, {0x01}, 1},  red gain msb
                         *{0x0d, 0x00, {0x10}, 1},  red gain lsb
                         *{0x0e, 0x00, {0x01}, 1},  blue gain msb
                         *{0x0f, 0x00, {0x10}, 1},  blue gain lsb
                         *{0x10, 0x00, {0x01}, 1}, green2 gain msb
                         *{0x11, 0x00, {0x10}, 1}, green2 gain lsb
                         */
                        {0x12, 0x00, {0x00}, 1},
                        {0x13, 0x00, {0x04}, 1}, /* weird effect on colors */
                        {0x14, 0x00, {0x00}, 1},
                        {0x15, 0x00, {0x06}, 1},
                        {0x16, 0x00, {0x01}, 1},
                        {0x17, 0x00, {0xe2}, 1}, /* vertical alignment */
                        {0x18, 0x00, {0x02}, 1},
                        {0x19, 0x00, {0x82}, 1}, /* don't mess with */
                        {0x1a, 0x00, {0x00}, 1},
                        {0x1b, 0x00, {0x20}, 1},
                        /* {0x1c, 0x00, {0x17}, 1}, contrast control */
                        {0x1d, 0x00, {0x80}, 1}, /* moving causes a mess */
                        {0x1e, 0x00, {0x08}, 1}, /* moving jams the camera */
                        {0x1f, 0x00, {0x0c}, 1},
                        {0x20, 0x00, {0x00}, 1},
                        {0, 0, {0}, 0}
                };
                err_code = sensor_write_regs(gspca_dev, vga_sensor2_init_data,
                                         ARRAY_SIZE(vga_sensor2_init_data));
        }
        return err_code;
}

static int sd_start(struct gspca_dev *gspca_dev)
{
        struct sd *sd = (struct sd *) gspca_dev;
        int err_code;

        sd->sof_read = 0;

        /* Some of the VGA cameras require the memory pointer
         * to be set to 0 again. We have been forced to start the
         * stream in sd_config() to detect the hardware, and closed it.
         * Thus, we need here to do a completely fresh and clean start. */
        err_code = zero_the_pointer(gspca_dev);
        if (err_code < 0)
                return err_code;

        err_code = stream_start(gspca_dev);
        if (err_code < 0)
                return err_code;

        if (sd->cam_type == CAM_TYPE_CIF) {
                err_code = start_cif_cam(gspca_dev);
        } else {
                err_code = start_vga_cam(gspca_dev);
        }
        if (err_code < 0)
                return err_code;

        return isoc_enable(gspca_dev);
}

static void sd_stopN(struct gspca_dev *gspca_dev)
{
        struct sd *sd = (struct sd *) gspca_dev;

        stream_stop(gspca_dev);
        /* Not all the cams need this, but even if not, probably a good idea */
        zero_the_pointer(gspca_dev);
        if (sd->do_lcd_stop)
                lcd_stop(gspca_dev);
}

static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
{
        struct sd *sd = (struct sd *) gspca_dev;
        u8 sign_reg = 7;  /* This reg and the next one used on CIF cams. */
        u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */
        static const u8 quick_clix_table[] =
        /*        0  1  2   3  4  5  6  7  8  9  10  11  12  13  14  15 */
                { 0, 4, 8, 12, 1, 2, 3, 5, 6, 9,  7, 10, 13, 11, 14, 15};
        if (sd->cam_type == CAM_TYPE_VGA) {
                sign_reg += 4;
                value_reg += 4;
        }

        /* Note register 7 is also seen as 0x8x or 0xCx in some dumps */
        if (val > 0) {
                sensor_write1(gspca_dev, sign_reg, 0x00);
        } else {
                sensor_write1(gspca_dev, sign_reg, 0x01);
                val = 257 - val;
        }
        /* Use lookup table for funky Argus QuickClix brightness */
        if (sd->do_lcd_stop)
                val = quick_clix_table[val];

        sensor_write1(gspca_dev, value_reg, val);
}

static void setexposure(struct gspca_dev *gspca_dev, s32 expo, s32 min_clockdiv)
{
        struct sd *sd = (struct sd *) gspca_dev;
        int exposure = MR97310A_EXPOSURE_DEFAULT;
        u8 buf[2];

        if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) {
                /* This cam does not like exposure settings < 300,
                   so scale 0 - 4095 to 300 - 4095 */
                exposure = (expo * 9267) / 10000 + 300;
                sensor_write1(gspca_dev, 3, exposure >> 4);
                sensor_write1(gspca_dev, 4, exposure & 0x0f);
        } else if (sd->sensor_type == 2) {
                exposure = expo;
                exposure >>= 3;
                sensor_write1(gspca_dev, 3, exposure >> 8);
                sensor_write1(gspca_dev, 4, exposure & 0xff);
        } else {
                /* We have both a clock divider and an exposure register.
                   We first calculate the clock divider, as that determines
                   the maximum exposure and then we calculate the exposure
                   register setting (which goes from 0 - 511).

                   Note our 0 - 4095 exposure is mapped to 0 - 511
                   milliseconds exposure time */
                u8 clockdiv = (60 * expo + 7999) / 8000;

                /* Limit framerate to not exceed usb bandwidth */
                if (clockdiv < min_clockdiv && gspca_dev->pixfmt.width >= 320)
                        clockdiv = min_clockdiv;
                else if (clockdiv < 2)
                        clockdiv = 2;

                if (sd->cam_type == CAM_TYPE_VGA && clockdiv < 4)
                        clockdiv = 4;

                /* Frame exposure time in ms = 1000 * clockdiv / 60 ->
                exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */
                exposure = (60 * 511 * expo) / (8000 * clockdiv);
                if (exposure > 511)
                        exposure = 511;

                /* exposure register value is reversed! */
                exposure = 511 - exposure;

                buf[0] = exposure & 0xff;
                buf[1] = exposure >> 8;
                sensor_write_reg(gspca_dev, 0x0e, 0, buf, 2);
                sensor_write1(gspca_dev, 0x02, clockdiv);
        }
}

static void setgain(struct gspca_dev *gspca_dev, s32 val)
{
        struct sd *sd = (struct sd *) gspca_dev;
        u8 gainreg;

        if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1)
                sensor_write1(gspca_dev, 0x0e, val);
        else if (sd->cam_type == CAM_TYPE_VGA && sd->sensor_type == 2)
                for (gainreg = 0x0a; gainreg < 0x11; gainreg += 2) {
                        sensor_write1(gspca_dev, gainreg, val >> 8);
                        sensor_write1(gspca_dev, gainreg + 1, val & 0xff);
                }
        else
                sensor_write1(gspca_dev, 0x10, val);
}

static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
{
        sensor_write1(gspca_dev, 0x1c, val);
}

static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
{
        struct gspca_dev *gspca_dev =
                container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
        struct sd *sd = (struct sd *)gspca_dev;

        gspca_dev->usb_err = 0;

        if (!gspca_dev->streaming)
                return 0;

        switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
                setbrightness(gspca_dev, ctrl->val);
                break;
        case V4L2_CID_CONTRAST:
                setcontrast(gspca_dev, ctrl->val);
                break;
        case V4L2_CID_EXPOSURE:
                setexposure(gspca_dev, sd->exposure->val,
                            sd->min_clockdiv ? sd->min_clockdiv->val : 0);
                break;
        case V4L2_CID_GAIN:
                setgain(gspca_dev, ctrl->val);
                break;
        }
        return gspca_dev->usb_err;
}

static const struct v4l2_ctrl_ops sd_ctrl_ops = {
        .s_ctrl = sd_s_ctrl,
};

static int sd_init_controls(struct gspca_dev *gspca_dev)
{
        struct sd *sd = (struct sd *)gspca_dev;
        struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
        static const struct v4l2_ctrl_config clockdiv = {
                .ops = &sd_ctrl_ops,
                .id = MR97310A_CID_CLOCKDIV,
                .type = V4L2_CTRL_TYPE_INTEGER,
                .name = "Minimum Clock Divider",
                .min = MR97310A_MIN_CLOCKDIV_MIN,
                .max = MR97310A_MIN_CLOCKDIV_MAX,
                .step = 1,
                .def = MR97310A_MIN_CLOCKDIV_DEFAULT,
        };
        bool has_brightness = false;
        bool has_argus_brightness = false;
        bool has_contrast = false;
        bool has_gain = false;
        bool has_cs_gain = false;
        bool has_exposure = false;
        bool has_clockdiv = false;

        gspca_dev->vdev.ctrl_handler = hdl;
        v4l2_ctrl_handler_init(hdl, 4);

        /* Setup controls depending on camera type */
        if (sd->cam_type == CAM_TYPE_CIF) {
                /* No brightness for sensor_type 0 */
                if (sd->sensor_type == 0)
                        has_exposure = has_gain = has_clockdiv = true;
                else
                        has_exposure = has_gain = has_brightness = true;
        } else {
                /* All controls need to be disabled if VGA sensor_type is 0 */
                if (sd->sensor_type == 0)
                        ; /* no controls! */
                else if (sd->sensor_type == 2)
                        has_exposure = has_cs_gain = has_contrast = true;
                else if (sd->do_lcd_stop)
                        has_exposure = has_gain = has_argus_brightness =
                                has_clockdiv = true;
                else
                        has_exposure = has_gain = has_brightness =
                                has_clockdiv = true;
        }

        /* Separate brightness control description for Argus QuickClix as it has
         * different limits from the other mr97310a cameras, and separate gain
         * control for Sakar CyberPix camera. */
        /*
         * This control is disabled for CIF type 1 and VGA type 0 cameras.
         * It does not quite act linearly for the Argus QuickClix camera,
         * but it does control brightness. The values are 0 - 15 only, and
         * the table above makes them act consecutively.
         */
        if (has_brightness)
                v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
                        V4L2_CID_BRIGHTNESS, -254, 255, 1,
                        MR97310A_BRIGHTNESS_DEFAULT);
        else if (has_argus_brightness)
                v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
                        V4L2_CID_BRIGHTNESS, 0, 15, 1,
                        MR97310A_BRIGHTNESS_DEFAULT);
        if (has_contrast)
                v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
                        V4L2_CID_CONTRAST, MR97310A_CONTRAST_MIN,
                        MR97310A_CONTRAST_MAX, 1, MR97310A_CONTRAST_DEFAULT);
        if (has_gain)
                v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
                        V4L2_CID_GAIN, MR97310A_GAIN_MIN, MR97310A_GAIN_MAX,
                        1, MR97310A_GAIN_DEFAULT);
        else if (has_cs_gain)
                v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_GAIN,
                        MR97310A_CS_GAIN_MIN, MR97310A_CS_GAIN_MAX,
                        1, MR97310A_CS_GAIN_DEFAULT);
        if (has_exposure)
                sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
                        V4L2_CID_EXPOSURE, MR97310A_EXPOSURE_MIN,
                        MR97310A_EXPOSURE_MAX, 1, MR97310A_EXPOSURE_DEFAULT);
        if (has_clockdiv)
                sd->min_clockdiv = v4l2_ctrl_new_custom(hdl, &clockdiv, NULL);

        if (hdl->error) {
                pr_err("Could not initialize controls\n");
                return hdl->error;
        }
        if (has_exposure && has_clockdiv)
                v4l2_ctrl_cluster(2, &sd->exposure);
        return 0;
}

/* Include pac common sof detection functions */
#include "pac_common.h"

static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                        u8 *data,               /* isoc packet */
                        int len)                /* iso packet length */
{
        struct sd *sd = (struct sd *) gspca_dev;
        unsigned char *sof;

        sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
        if (sof) {
                int n;

                /* finish decoding current frame */
                n = sof - data;
                if (n > sizeof pac_sof_marker)
                        n -= sizeof pac_sof_marker;
                else
                        n = 0;
                gspca_frame_add(gspca_dev, LAST_PACKET,
                                        data, n);
                /* Start next frame. */
                gspca_frame_add(gspca_dev, FIRST_PACKET,
                        pac_sof_marker, sizeof pac_sof_marker);
                len -= sof - data;
                data = sof;
        }
        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}

/* sub-driver description */
static const struct sd_desc sd_desc = {
        .name = MODULE_NAME,
        .config = sd_config,
        .init = sd_init,
        .init_controls = sd_init_controls,
        .start = sd_start,
        .stopN = sd_stopN,
        .pkt_scan = sd_pkt_scan,
};

/* -- module initialisation -- */
static const struct usb_device_id device_table[] = {
        {USB_DEVICE(0x08ca, 0x0110)},   /* Trust Spyc@m 100 */
        {USB_DEVICE(0x08ca, 0x0111)},   /* Aiptek Pencam VGA+ */
        {USB_DEVICE(0x093a, 0x010f)},   /* All other known MR97310A VGA cams */
        {USB_DEVICE(0x093a, 0x010e)},   /* All known MR97310A CIF cams */
        {}
};
MODULE_DEVICE_TABLE(usb, device_table);

/* -- device connect -- */
static int sd_probe(struct usb_interface *intf,
                    const struct usb_device_id *id)
{
        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
                               THIS_MODULE);
}

static struct usb_driver sd_driver = {
        .name = MODULE_NAME,
        .id_table = device_table,
        .probe = sd_probe,
        .disconnect = gspca_disconnect,
#ifdef CONFIG_PM
        .suspend = gspca_suspend,
        .resume = gspca_resume,
        .reset_resume = gspca_resume,
#endif
};

module_usb_driver(sd_driver);