162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2001 Jean-Fredric Clere, Nikolas Zimmermann, Georg Acher
462306a36Sopenharmony_ci *		      Mark Cave-Ayland, Carlo E Prelz, Dick Streefland
562306a36Sopenharmony_ci * Copyright (c) 2002, 2003 Tuukka Toivonen
662306a36Sopenharmony_ci * Copyright (c) 2008 Erik Andrén
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * P/N 861037:      Sensor HDCS1000        ASIC STV0600
962306a36Sopenharmony_ci * P/N 861050-0010: Sensor HDCS1000        ASIC STV0600
1062306a36Sopenharmony_ci * P/N 861050-0020: Sensor Photobit PB100  ASIC STV0600-1 - QuickCam Express
1162306a36Sopenharmony_ci * P/N 861055:      Sensor ST VV6410       ASIC STV0610   - LEGO cam
1262306a36Sopenharmony_ci * P/N 861075-0040: Sensor HDCS1000        ASIC
1362306a36Sopenharmony_ci * P/N 961179-0700: Sensor ST VV6410       ASIC STV0602   - Dexxa WebCam USB
1462306a36Sopenharmony_ci * P/N 861040-0000: Sensor ST VV6410       ASIC STV0610   - QuickCam Web
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#include <linux/input.h>
2062306a36Sopenharmony_ci#include "stv06xx_sensor.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciMODULE_AUTHOR("Erik Andrén");
2362306a36Sopenharmony_ciMODULE_DESCRIPTION("STV06XX USB Camera Driver");
2462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic bool dump_bridge;
2762306a36Sopenharmony_cistatic bool dump_sensor;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ciint stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	int err;
3262306a36Sopenharmony_ci	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
3362306a36Sopenharmony_ci	struct usb_device *udev = sd->gspca_dev.dev;
3462306a36Sopenharmony_ci	__u8 *buf = sd->gspca_dev.usb_buf;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	u8 len = (i2c_data > 0xff) ? 2 : 1;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	buf[0] = i2c_data & 0xff;
3962306a36Sopenharmony_ci	buf[1] = (i2c_data >> 8) & 0xff;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
4262306a36Sopenharmony_ci			      0x04, 0x40, address, 0, buf, len,
4362306a36Sopenharmony_ci			      STV06XX_URB_MSG_TIMEOUT);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_CONF, "Written 0x%x to address 0x%x, status: %d\n",
4662306a36Sopenharmony_ci		  i2c_data, address, err);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	return (err < 0) ? err : 0;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciint stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	int err;
5462306a36Sopenharmony_ci	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
5562306a36Sopenharmony_ci	struct usb_device *udev = sd->gspca_dev.dev;
5662306a36Sopenharmony_ci	__u8 *buf = sd->gspca_dev.usb_buf;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
5962306a36Sopenharmony_ci			      0x04, 0xc0, address, 0, buf, 1,
6062306a36Sopenharmony_ci			      STV06XX_URB_MSG_TIMEOUT);
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	*i2c_data = buf[0];
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_CONF, "Reading 0x%x from address 0x%x, status %d\n",
6562306a36Sopenharmony_ci		  *i2c_data, address, err);
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	return (err < 0) ? err : 0;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/* Wraps the normal write sensor bytes / words functions for writing a
7162306a36Sopenharmony_ci   single value */
7262306a36Sopenharmony_ciint stv06xx_write_sensor(struct sd *sd, u8 address, u16 value)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	if (sd->sensor->i2c_len == 2) {
7562306a36Sopenharmony_ci		u16 data[2] = { address, value };
7662306a36Sopenharmony_ci		return stv06xx_write_sensor_words(sd, data, 1);
7762306a36Sopenharmony_ci	} else {
7862306a36Sopenharmony_ci		u8 data[2] = { address, value };
7962306a36Sopenharmony_ci		return stv06xx_write_sensor_bytes(sd, data, 1);
8062306a36Sopenharmony_ci	}
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic int stv06xx_write_sensor_finish(struct sd *sd)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	int err = 0;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (sd->bridge == BRIDGE_STV610) {
8862306a36Sopenharmony_ci		struct usb_device *udev = sd->gspca_dev.dev;
8962306a36Sopenharmony_ci		__u8 *buf = sd->gspca_dev.usb_buf;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci		buf[0] = 0;
9262306a36Sopenharmony_ci		err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
9362306a36Sopenharmony_ci				      0x04, 0x40, 0x1704, 0, buf, 1,
9462306a36Sopenharmony_ci				      STV06XX_URB_MSG_TIMEOUT);
9562306a36Sopenharmony_ci	}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci	return (err < 0) ? err : 0;
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ciint stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	int err, i, j;
10362306a36Sopenharmony_ci	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
10462306a36Sopenharmony_ci	struct usb_device *udev = sd->gspca_dev.dev;
10562306a36Sopenharmony_ci	__u8 *buf = sd->gspca_dev.usb_buf;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_CONF, "I2C: Command buffer contains %d entries\n",
10862306a36Sopenharmony_ci		  len);
10962306a36Sopenharmony_ci	for (i = 0; i < len;) {
11062306a36Sopenharmony_ci		/* Build the command buffer */
11162306a36Sopenharmony_ci		memset(buf, 0, I2C_BUFFER_LENGTH);
11262306a36Sopenharmony_ci		for (j = 0; j < I2C_MAX_BYTES && i < len; j++, i++) {
11362306a36Sopenharmony_ci			buf[j] = data[2*i];
11462306a36Sopenharmony_ci			buf[0x10 + j] = data[2*i+1];
11562306a36Sopenharmony_ci			gspca_dbg(gspca_dev, D_CONF, "I2C: Writing 0x%02x to reg 0x%02x\n",
11662306a36Sopenharmony_ci				  data[2*i+1], data[2*i]);
11762306a36Sopenharmony_ci		}
11862306a36Sopenharmony_ci		buf[0x20] = sd->sensor->i2c_addr;
11962306a36Sopenharmony_ci		buf[0x21] = j - 1; /* Number of commands to send - 1 */
12062306a36Sopenharmony_ci		buf[0x22] = I2C_WRITE_CMD;
12162306a36Sopenharmony_ci		err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
12262306a36Sopenharmony_ci				      0x04, 0x40, 0x0400, 0, buf,
12362306a36Sopenharmony_ci				      I2C_BUFFER_LENGTH,
12462306a36Sopenharmony_ci				      STV06XX_URB_MSG_TIMEOUT);
12562306a36Sopenharmony_ci		if (err < 0)
12662306a36Sopenharmony_ci			return err;
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci	return stv06xx_write_sensor_finish(sd);
12962306a36Sopenharmony_ci}
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ciint stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len)
13262306a36Sopenharmony_ci{
13362306a36Sopenharmony_ci	int err, i, j;
13462306a36Sopenharmony_ci	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
13562306a36Sopenharmony_ci	struct usb_device *udev = sd->gspca_dev.dev;
13662306a36Sopenharmony_ci	__u8 *buf = sd->gspca_dev.usb_buf;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_CONF, "I2C: Command buffer contains %d entries\n",
13962306a36Sopenharmony_ci		  len);
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	for (i = 0; i < len;) {
14262306a36Sopenharmony_ci		/* Build the command buffer */
14362306a36Sopenharmony_ci		memset(buf, 0, I2C_BUFFER_LENGTH);
14462306a36Sopenharmony_ci		for (j = 0; j < I2C_MAX_WORDS && i < len; j++, i++) {
14562306a36Sopenharmony_ci			buf[j] = data[2*i];
14662306a36Sopenharmony_ci			buf[0x10 + j * 2] = data[2*i+1];
14762306a36Sopenharmony_ci			buf[0x10 + j * 2 + 1] = data[2*i+1] >> 8;
14862306a36Sopenharmony_ci			gspca_dbg(gspca_dev, D_CONF, "I2C: Writing 0x%04x to reg 0x%02x\n",
14962306a36Sopenharmony_ci				  data[2*i+1], data[2*i]);
15062306a36Sopenharmony_ci		}
15162306a36Sopenharmony_ci		buf[0x20] = sd->sensor->i2c_addr;
15262306a36Sopenharmony_ci		buf[0x21] = j - 1; /* Number of commands to send - 1 */
15362306a36Sopenharmony_ci		buf[0x22] = I2C_WRITE_CMD;
15462306a36Sopenharmony_ci		err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
15562306a36Sopenharmony_ci				0x04, 0x40, 0x0400, 0, buf,
15662306a36Sopenharmony_ci				I2C_BUFFER_LENGTH,
15762306a36Sopenharmony_ci				STV06XX_URB_MSG_TIMEOUT);
15862306a36Sopenharmony_ci		if (err < 0)
15962306a36Sopenharmony_ci			return err;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci	return stv06xx_write_sensor_finish(sd);
16262306a36Sopenharmony_ci}
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ciint stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value)
16562306a36Sopenharmony_ci{
16662306a36Sopenharmony_ci	int err;
16762306a36Sopenharmony_ci	struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
16862306a36Sopenharmony_ci	struct usb_device *udev = sd->gspca_dev.dev;
16962306a36Sopenharmony_ci	__u8 *buf = sd->gspca_dev.usb_buf;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	err = stv06xx_write_bridge(sd, STV_I2C_FLUSH, sd->sensor->i2c_flush);
17262306a36Sopenharmony_ci	if (err < 0)
17362306a36Sopenharmony_ci		return err;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	/* Clear mem */
17662306a36Sopenharmony_ci	memset(buf, 0, I2C_BUFFER_LENGTH);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	buf[0] = address;
17962306a36Sopenharmony_ci	buf[0x20] = sd->sensor->i2c_addr;
18062306a36Sopenharmony_ci	buf[0x21] = 0;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/* Read I2C register */
18362306a36Sopenharmony_ci	buf[0x22] = I2C_READ_CMD;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
18662306a36Sopenharmony_ci			      0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH,
18762306a36Sopenharmony_ci			      STV06XX_URB_MSG_TIMEOUT);
18862306a36Sopenharmony_ci	if (err < 0) {
18962306a36Sopenharmony_ci		pr_err("I2C: Read error writing address: %d\n", err);
19062306a36Sopenharmony_ci		return err;
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	err = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
19462306a36Sopenharmony_ci			      0x04, 0xc0, 0x1410, 0, buf, sd->sensor->i2c_len,
19562306a36Sopenharmony_ci			      STV06XX_URB_MSG_TIMEOUT);
19662306a36Sopenharmony_ci	if (sd->sensor->i2c_len == 2)
19762306a36Sopenharmony_ci		*value = buf[0] | (buf[1] << 8);
19862306a36Sopenharmony_ci	else
19962306a36Sopenharmony_ci		*value = buf[0];
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_CONF, "I2C: Read 0x%x from address 0x%x, status: %d\n",
20262306a36Sopenharmony_ci		  *value, address, err);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return (err < 0) ? err : 0;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/* Dumps all bridge registers */
20862306a36Sopenharmony_cistatic void stv06xx_dump_bridge(struct sd *sd)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	int i;
21162306a36Sopenharmony_ci	u8 data, buf;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	pr_info("Dumping all stv06xx bridge registers\n");
21462306a36Sopenharmony_ci	for (i = 0x1400; i < 0x160f; i++) {
21562306a36Sopenharmony_ci		stv06xx_read_bridge(sd, i, &data);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci		pr_info("Read 0x%x from address 0x%x\n", data, i);
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	pr_info("Testing stv06xx bridge registers for writability\n");
22162306a36Sopenharmony_ci	for (i = 0x1400; i < 0x160f; i++) {
22262306a36Sopenharmony_ci		stv06xx_read_bridge(sd, i, &data);
22362306a36Sopenharmony_ci		buf = data;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		stv06xx_write_bridge(sd, i, 0xff);
22662306a36Sopenharmony_ci		stv06xx_read_bridge(sd, i, &data);
22762306a36Sopenharmony_ci		if (data == 0xff)
22862306a36Sopenharmony_ci			pr_info("Register 0x%x is read/write\n", i);
22962306a36Sopenharmony_ci		else if (data != buf)
23062306a36Sopenharmony_ci			pr_info("Register 0x%x is read/write, but only partially\n",
23162306a36Sopenharmony_ci				i);
23262306a36Sopenharmony_ci		else
23362306a36Sopenharmony_ci			pr_info("Register 0x%x is read-only\n", i);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci		stv06xx_write_bridge(sd, i, buf);
23662306a36Sopenharmony_ci	}
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci/* this function is called at probe and resume time */
24062306a36Sopenharmony_cistatic int stv06xx_init(struct gspca_dev *gspca_dev)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
24362306a36Sopenharmony_ci	int err;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_PROBE, "Initializing camera\n");
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	/* Let the usb init settle for a bit
24862306a36Sopenharmony_ci	   before performing the initialization */
24962306a36Sopenharmony_ci	msleep(250);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	err = sd->sensor->init(sd);
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (dump_sensor && sd->sensor->dump)
25462306a36Sopenharmony_ci		sd->sensor->dump(sd);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	return (err < 0) ? err : 0;
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci/* this function is called at probe time */
26062306a36Sopenharmony_cistatic int stv06xx_init_controls(struct gspca_dev *gspca_dev)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_PROBE, "Initializing controls\n");
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	gspca_dev->vdev.ctrl_handler = &gspca_dev->ctrl_handler;
26762306a36Sopenharmony_ci	return sd->sensor->init_controls(sd);
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/* Start the camera */
27162306a36Sopenharmony_cistatic int stv06xx_start(struct gspca_dev *gspca_dev)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
27462306a36Sopenharmony_ci	struct usb_host_interface *alt;
27562306a36Sopenharmony_ci	struct usb_interface *intf;
27662306a36Sopenharmony_ci	int err, packet_size;
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
27962306a36Sopenharmony_ci	alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
28062306a36Sopenharmony_ci	if (!alt) {
28162306a36Sopenharmony_ci		gspca_err(gspca_dev, "Couldn't get altsetting\n");
28262306a36Sopenharmony_ci		return -EIO;
28362306a36Sopenharmony_ci	}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (alt->desc.bNumEndpoints < 1)
28662306a36Sopenharmony_ci		return -ENODEV;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
28962306a36Sopenharmony_ci	err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size);
29062306a36Sopenharmony_ci	if (err < 0)
29162306a36Sopenharmony_ci		return err;
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	/* Prepare the sensor for start */
29462306a36Sopenharmony_ci	err = sd->sensor->start(sd);
29562306a36Sopenharmony_ci	if (err < 0)
29662306a36Sopenharmony_ci		goto out;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	/* Start isochronous streaming */
29962306a36Sopenharmony_ci	err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 1);
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ciout:
30262306a36Sopenharmony_ci	if (err < 0)
30362306a36Sopenharmony_ci		gspca_dbg(gspca_dev, D_STREAM, "Starting stream failed\n");
30462306a36Sopenharmony_ci	else
30562306a36Sopenharmony_ci		gspca_dbg(gspca_dev, D_STREAM, "Started streaming\n");
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	return (err < 0) ? err : 0;
30862306a36Sopenharmony_ci}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_cistatic int stv06xx_isoc_init(struct gspca_dev *gspca_dev)
31162306a36Sopenharmony_ci{
31262306a36Sopenharmony_ci	struct usb_interface_cache *intfc;
31362306a36Sopenharmony_ci	struct usb_host_interface *alt;
31462306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	intfc = gspca_dev->dev->actconfig->intf_cache[0];
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	if (intfc->num_altsetting < 2)
31962306a36Sopenharmony_ci		return -ENODEV;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	alt = &intfc->altsetting[1];
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if (alt->desc.bNumEndpoints < 1)
32462306a36Sopenharmony_ci		return -ENODEV;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	/* Start isoc bandwidth "negotiation" at max isoc bandwidth */
32762306a36Sopenharmony_ci	alt->endpoint[0].desc.wMaxPacketSize =
32862306a36Sopenharmony_ci		cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	return 0;
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic int stv06xx_isoc_nego(struct gspca_dev *gspca_dev)
33462306a36Sopenharmony_ci{
33562306a36Sopenharmony_ci	int ret, packet_size, min_packet_size;
33662306a36Sopenharmony_ci	struct usb_host_interface *alt;
33762306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/*
34062306a36Sopenharmony_ci	 * Existence of altsetting and endpoint was verified in
34162306a36Sopenharmony_ci	 * stv06xx_isoc_init()
34262306a36Sopenharmony_ci	 */
34362306a36Sopenharmony_ci	alt = &gspca_dev->dev->actconfig->intf_cache[0]->altsetting[1];
34462306a36Sopenharmony_ci	packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
34562306a36Sopenharmony_ci	min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode];
34662306a36Sopenharmony_ci	if (packet_size <= min_packet_size)
34762306a36Sopenharmony_ci		return -EIO;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	packet_size -= 100;
35062306a36Sopenharmony_ci	if (packet_size < min_packet_size)
35162306a36Sopenharmony_ci		packet_size = min_packet_size;
35262306a36Sopenharmony_ci	alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
35562306a36Sopenharmony_ci	if (ret < 0)
35662306a36Sopenharmony_ci		gspca_err(gspca_dev, "set alt 1 err %d\n", ret);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	return ret;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic void stv06xx_stopN(struct gspca_dev *gspca_dev)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	int err;
36462306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/* stop ISO-streaming */
36762306a36Sopenharmony_ci	err = stv06xx_write_bridge(sd, STV_ISO_ENABLE, 0);
36862306a36Sopenharmony_ci	if (err < 0)
36962306a36Sopenharmony_ci		goto out;
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_ci	err = sd->sensor->stop(sd);
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ciout:
37462306a36Sopenharmony_ci	if (err < 0)
37562306a36Sopenharmony_ci		gspca_dbg(gspca_dev, D_STREAM, "Failed to stop stream\n");
37662306a36Sopenharmony_ci	else
37762306a36Sopenharmony_ci		gspca_dbg(gspca_dev, D_STREAM, "Stopped streaming\n");
37862306a36Sopenharmony_ci}
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci/*
38162306a36Sopenharmony_ci * Analyse an USB packet of the data stream and store it appropriately.
38262306a36Sopenharmony_ci * Each packet contains an integral number of chunks. Each chunk has
38362306a36Sopenharmony_ci * 2-bytes identification, followed by 2-bytes that describe the chunk
38462306a36Sopenharmony_ci * length. Known/guessed chunk identifications are:
38562306a36Sopenharmony_ci * 8001/8005/C001/C005 - Begin new frame
38662306a36Sopenharmony_ci * 8002/8006/C002/C006 - End frame
38762306a36Sopenharmony_ci * 0200/4200           - Contains actual image data, bayer or compressed
38862306a36Sopenharmony_ci * 0005                - 11 bytes of unknown data
38962306a36Sopenharmony_ci * 0100                - 2 bytes of unknown data
39062306a36Sopenharmony_ci * The 0005 and 0100 chunks seem to appear only in compressed stream.
39162306a36Sopenharmony_ci */
39262306a36Sopenharmony_cistatic void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
39362306a36Sopenharmony_ci			u8 *data,			/* isoc packet */
39462306a36Sopenharmony_ci			int len)			/* iso packet length */
39562306a36Sopenharmony_ci{
39662306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_PACK, "Packet of length %d arrived\n", len);
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	/* A packet may contain several frames
40162306a36Sopenharmony_ci	   loop until the whole packet is reached */
40262306a36Sopenharmony_ci	while (len) {
40362306a36Sopenharmony_ci		int id, chunk_len;
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci		if (len < 4) {
40662306a36Sopenharmony_ci			gspca_dbg(gspca_dev, D_PACK, "Packet is smaller than 4 bytes\n");
40762306a36Sopenharmony_ci			return;
40862306a36Sopenharmony_ci		}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		/* Capture the id */
41162306a36Sopenharmony_ci		id = (data[0] << 8) | data[1];
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		/* Capture the chunk length */
41462306a36Sopenharmony_ci		chunk_len = (data[2] << 8) | data[3];
41562306a36Sopenharmony_ci		gspca_dbg(gspca_dev, D_PACK, "Chunk id: %x, length: %d\n",
41662306a36Sopenharmony_ci			  id, chunk_len);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		data += 4;
41962306a36Sopenharmony_ci		len -= 4;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci		if (len < chunk_len) {
42262306a36Sopenharmony_ci			gspca_err(gspca_dev, "URB packet length is smaller than the specified chunk length\n");
42362306a36Sopenharmony_ci			gspca_dev->last_packet_type = DISCARD_PACKET;
42462306a36Sopenharmony_ci			return;
42562306a36Sopenharmony_ci		}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci		/* First byte seem to be 02=data 2nd byte is unknown??? */
42862306a36Sopenharmony_ci		if (sd->bridge == BRIDGE_ST6422 && (id & 0xff00) == 0x0200)
42962306a36Sopenharmony_ci			goto frame_data;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		switch (id) {
43262306a36Sopenharmony_ci		case 0x0200:
43362306a36Sopenharmony_ci		case 0x4200:
43462306a36Sopenharmony_ciframe_data:
43562306a36Sopenharmony_ci			gspca_dbg(gspca_dev, D_PACK, "Frame data packet detected\n");
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci			if (sd->to_skip) {
43862306a36Sopenharmony_ci				int skip = (sd->to_skip < chunk_len) ?
43962306a36Sopenharmony_ci					    sd->to_skip : chunk_len;
44062306a36Sopenharmony_ci				data += skip;
44162306a36Sopenharmony_ci				len -= skip;
44262306a36Sopenharmony_ci				chunk_len -= skip;
44362306a36Sopenharmony_ci				sd->to_skip -= skip;
44462306a36Sopenharmony_ci			}
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci			gspca_frame_add(gspca_dev, INTER_PACKET,
44762306a36Sopenharmony_ci					data, chunk_len);
44862306a36Sopenharmony_ci			break;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci		case 0x8001:
45162306a36Sopenharmony_ci		case 0x8005:
45262306a36Sopenharmony_ci		case 0xc001:
45362306a36Sopenharmony_ci		case 0xc005:
45462306a36Sopenharmony_ci			gspca_dbg(gspca_dev, D_PACK, "Starting new frame\n");
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci			/* Create a new frame, chunk length should be zero */
45762306a36Sopenharmony_ci			gspca_frame_add(gspca_dev, FIRST_PACKET,
45862306a36Sopenharmony_ci					NULL, 0);
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci			if (sd->bridge == BRIDGE_ST6422)
46162306a36Sopenharmony_ci				sd->to_skip = gspca_dev->pixfmt.width * 4;
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci			if (chunk_len)
46462306a36Sopenharmony_ci				gspca_err(gspca_dev, "Chunk length is non-zero on a SOF\n");
46562306a36Sopenharmony_ci			break;
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci		case 0x8002:
46862306a36Sopenharmony_ci		case 0x8006:
46962306a36Sopenharmony_ci		case 0xc002:
47062306a36Sopenharmony_ci			gspca_dbg(gspca_dev, D_PACK, "End of frame detected\n");
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci			/* Complete the last frame (if any) */
47362306a36Sopenharmony_ci			gspca_frame_add(gspca_dev, LAST_PACKET,
47462306a36Sopenharmony_ci					NULL, 0);
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci			if (chunk_len)
47762306a36Sopenharmony_ci				gspca_err(gspca_dev, "Chunk length is non-zero on a EOF\n");
47862306a36Sopenharmony_ci			break;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci		case 0x0005:
48162306a36Sopenharmony_ci			gspca_dbg(gspca_dev, D_PACK, "Chunk 0x005 detected\n");
48262306a36Sopenharmony_ci			/* Unknown chunk with 11 bytes of data,
48362306a36Sopenharmony_ci			   occurs just before end of each frame
48462306a36Sopenharmony_ci			   in compressed mode */
48562306a36Sopenharmony_ci			break;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		case 0x0100:
48862306a36Sopenharmony_ci			gspca_dbg(gspca_dev, D_PACK, "Chunk 0x0100 detected\n");
48962306a36Sopenharmony_ci			/* Unknown chunk with 2 bytes of data,
49062306a36Sopenharmony_ci			   occurs 2-3 times per USB interrupt */
49162306a36Sopenharmony_ci			break;
49262306a36Sopenharmony_ci		case 0x42ff:
49362306a36Sopenharmony_ci			gspca_dbg(gspca_dev, D_PACK, "Chunk 0x42ff detected\n");
49462306a36Sopenharmony_ci			/* Special chunk seen sometimes on the ST6422 */
49562306a36Sopenharmony_ci			break;
49662306a36Sopenharmony_ci		default:
49762306a36Sopenharmony_ci			gspca_dbg(gspca_dev, D_PACK, "Unknown chunk 0x%04x detected\n",
49862306a36Sopenharmony_ci				  id);
49962306a36Sopenharmony_ci			/* Unknown chunk */
50062306a36Sopenharmony_ci		}
50162306a36Sopenharmony_ci		data    += chunk_len;
50262306a36Sopenharmony_ci		len     -= chunk_len;
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci}
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_INPUT)
50762306a36Sopenharmony_cistatic int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
50862306a36Sopenharmony_ci			u8 *data,		/* interrupt packet data */
50962306a36Sopenharmony_ci			int len)		/* interrupt packet length */
51062306a36Sopenharmony_ci{
51162306a36Sopenharmony_ci	int ret = -EINVAL;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (len == 1 && (data[0] == 0x80 || data[0] == 0x10)) {
51462306a36Sopenharmony_ci		input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
51562306a36Sopenharmony_ci		input_sync(gspca_dev->input_dev);
51662306a36Sopenharmony_ci		ret = 0;
51762306a36Sopenharmony_ci	}
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	if (len == 1 && (data[0] == 0x88 || data[0] == 0x11)) {
52062306a36Sopenharmony_ci		input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
52162306a36Sopenharmony_ci		input_sync(gspca_dev->input_dev);
52262306a36Sopenharmony_ci		ret = 0;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	return ret;
52662306a36Sopenharmony_ci}
52762306a36Sopenharmony_ci#endif
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic int stv06xx_config(struct gspca_dev *gspca_dev,
53062306a36Sopenharmony_ci			  const struct usb_device_id *id);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic void stv06xx_probe_error(struct gspca_dev *gspca_dev)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	struct sd *sd = (struct sd *)gspca_dev;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	kfree(sd->sensor_priv);
53762306a36Sopenharmony_ci	sd->sensor_priv = NULL;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci/* sub-driver description */
54162306a36Sopenharmony_cistatic const struct sd_desc sd_desc = {
54262306a36Sopenharmony_ci	.name = MODULE_NAME,
54362306a36Sopenharmony_ci	.config = stv06xx_config,
54462306a36Sopenharmony_ci	.init = stv06xx_init,
54562306a36Sopenharmony_ci	.init_controls = stv06xx_init_controls,
54662306a36Sopenharmony_ci	.probe_error = stv06xx_probe_error,
54762306a36Sopenharmony_ci	.start = stv06xx_start,
54862306a36Sopenharmony_ci	.stopN = stv06xx_stopN,
54962306a36Sopenharmony_ci	.pkt_scan = stv06xx_pkt_scan,
55062306a36Sopenharmony_ci	.isoc_init = stv06xx_isoc_init,
55162306a36Sopenharmony_ci	.isoc_nego = stv06xx_isoc_nego,
55262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_INPUT)
55362306a36Sopenharmony_ci	.int_pkt_scan = sd_int_pkt_scan,
55462306a36Sopenharmony_ci#endif
55562306a36Sopenharmony_ci};
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci/* This function is called at probe time */
55862306a36Sopenharmony_cistatic int stv06xx_config(struct gspca_dev *gspca_dev,
55962306a36Sopenharmony_ci			  const struct usb_device_id *id)
56062306a36Sopenharmony_ci{
56162306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_PROBE, "Configuring camera\n");
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	sd->bridge = id->driver_info;
56662306a36Sopenharmony_ci	gspca_dev->sd_desc = &sd_desc;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	if (dump_bridge)
56962306a36Sopenharmony_ci		stv06xx_dump_bridge(sd);
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	sd->sensor = &stv06xx_sensor_st6422;
57262306a36Sopenharmony_ci	if (!sd->sensor->probe(sd))
57362306a36Sopenharmony_ci		return 0;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	sd->sensor = &stv06xx_sensor_vv6410;
57662306a36Sopenharmony_ci	if (!sd->sensor->probe(sd))
57762306a36Sopenharmony_ci		return 0;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	sd->sensor = &stv06xx_sensor_hdcs1x00;
58062306a36Sopenharmony_ci	if (!sd->sensor->probe(sd))
58162306a36Sopenharmony_ci		return 0;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	sd->sensor = &stv06xx_sensor_hdcs1020;
58462306a36Sopenharmony_ci	if (!sd->sensor->probe(sd))
58562306a36Sopenharmony_ci		return 0;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	sd->sensor = &stv06xx_sensor_pb0100;
58862306a36Sopenharmony_ci	if (!sd->sensor->probe(sd))
58962306a36Sopenharmony_ci		return 0;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	sd->sensor = NULL;
59262306a36Sopenharmony_ci	return -ENODEV;
59362306a36Sopenharmony_ci}
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci
59762306a36Sopenharmony_ci/* -- module initialisation -- */
59862306a36Sopenharmony_cistatic const struct usb_device_id device_table[] = {
59962306a36Sopenharmony_ci	{USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 },	/* QuickCam Express */
60062306a36Sopenharmony_ci	{USB_DEVICE(0x046d, 0x0850), .driver_info = BRIDGE_STV610 },	/* LEGO cam / QuickCam Web */
60162306a36Sopenharmony_ci	{USB_DEVICE(0x046d, 0x0870), .driver_info = BRIDGE_STV602 },	/* Dexxa WebCam USB */
60262306a36Sopenharmony_ci	{USB_DEVICE(0x046D, 0x08F0), .driver_info = BRIDGE_ST6422 },	/* QuickCam Messenger */
60362306a36Sopenharmony_ci	{USB_DEVICE(0x046D, 0x08F5), .driver_info = BRIDGE_ST6422 },	/* QuickCam Communicate */
60462306a36Sopenharmony_ci	{USB_DEVICE(0x046D, 0x08F6), .driver_info = BRIDGE_ST6422 },	/* QuickCam Messenger (new) */
60562306a36Sopenharmony_ci	{}
60662306a36Sopenharmony_ci};
60762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, device_table);
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci/* -- device connect -- */
61062306a36Sopenharmony_cistatic int sd_probe(struct usb_interface *intf,
61162306a36Sopenharmony_ci			const struct usb_device_id *id)
61262306a36Sopenharmony_ci{
61362306a36Sopenharmony_ci	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
61462306a36Sopenharmony_ci			       THIS_MODULE);
61562306a36Sopenharmony_ci}
61662306a36Sopenharmony_ci
61762306a36Sopenharmony_cistatic void sd_disconnect(struct usb_interface *intf)
61862306a36Sopenharmony_ci{
61962306a36Sopenharmony_ci	struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
62062306a36Sopenharmony_ci	struct sd *sd = (struct sd *) gspca_dev;
62162306a36Sopenharmony_ci	void *priv = sd->sensor_priv;
62262306a36Sopenharmony_ci	gspca_dbg(gspca_dev, D_PROBE, "Disconnecting the stv06xx device\n");
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	sd->sensor = NULL;
62562306a36Sopenharmony_ci	gspca_disconnect(intf);
62662306a36Sopenharmony_ci	kfree(priv);
62762306a36Sopenharmony_ci}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_cistatic struct usb_driver sd_driver = {
63062306a36Sopenharmony_ci	.name = MODULE_NAME,
63162306a36Sopenharmony_ci	.id_table = device_table,
63262306a36Sopenharmony_ci	.probe = sd_probe,
63362306a36Sopenharmony_ci	.disconnect = sd_disconnect,
63462306a36Sopenharmony_ci#ifdef CONFIG_PM
63562306a36Sopenharmony_ci	.suspend = gspca_suspend,
63662306a36Sopenharmony_ci	.resume = gspca_resume,
63762306a36Sopenharmony_ci	.reset_resume = gspca_resume,
63862306a36Sopenharmony_ci#endif
63962306a36Sopenharmony_ci};
64062306a36Sopenharmony_ci
64162306a36Sopenharmony_cimodule_usb_driver(sd_driver);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_cimodule_param(dump_bridge, bool, S_IRUGO | S_IWUSR);
64462306a36Sopenharmony_ciMODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup");
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_cimodule_param(dump_sensor, bool, S_IRUGO | S_IWUSR);
64762306a36Sopenharmony_ciMODULE_PARM_DESC(dump_sensor, "Dumps all sensor registers at startup");
648