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