1078 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1078 lines
		
	
	
		
			29 KiB
		
	
	
	
		
			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);
 |