|  | // 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); |