1
0
Files
kernel-49/drivers/media/usb/gspca/w996Xcf.c
Greg Kroah-Hartman b73b4446ac Merge 4.9.195 into android-4.9-q
Changes in 4.9.195
	Revert "Bluetooth: validate BLE connection interval updates"
	IB/core: Add an unbound WQ type to the new CQ API
	HID: prodikeys: Fix general protection fault during probe
	HID: logitech: Fix general protection fault caused by Logitech driver
	HID: hidraw: Fix invalid read in hidraw_ioctl
	mtd: cfi_cmdset_0002: Use chip_good() to retry in do_write_oneword()
	crypto: talitos - fix missing break in switch statement
	media: tvp5150: fix switch exit in set control handler
	ASoC: fsl: Fix of-node refcount unbalance in fsl_ssi_probe_from_dt()
	ALSA: hda - Add laptop imic fixup for ASUS M9V laptop
	objtool: Clobber user CFLAGS variable
	mac80211: Print text for disassociation reason
	mac80211: handle deauthentication/disassociation from TDLS peer
	power: supply: sysfs: ratelimit property read error message
	locking/lockdep: Add debug_locks check in __lock_downgrade()
	irqchip/gic-v3-its: Fix LPI release for Multi-MSI devices
	f2fs: check all the data segments against all node ones
	Revert "f2fs: avoid out-of-range memory access"
	f2fs: fix to do sanity check on segment bitmap of LFS curseg
	drm: Flush output polling on shutdown
	xfs: don't crash on null attr fork xfs_bmapi_read
	Bluetooth: btrtl: Additional Realtek 8822CE Bluetooth devices
	arcnet: provide a buffer big enough to actually receive packets
	cdc_ncm: fix divide-by-zero caused by invalid wMaxPacketSize
	macsec: drop skb sk before calling gro_cells_receive
	net/phy: fix DP83865 10 Mbps HDX loopback disable function
	net: qrtr: Stop rx_worker before freeing node
	openvswitch: change type of UPCALL_PID attribute to NLA_UNSPEC
	ppp: Fix memory leak in ppp_write
	sch_netem: fix a divide by zero in tabledist()
	skge: fix checksum byte order
	usbnet: ignore endpoints with invalid wMaxPacketSize
	usbnet: sanity checking of packet sizes and device mtu
	mISDN: enforce CAP_NET_RAW for raw sockets
	appletalk: enforce CAP_NET_RAW for raw sockets
	ax25: enforce CAP_NET_RAW for raw sockets
	ieee802154: enforce CAP_NET_RAW for raw sockets
	nfc: enforce CAP_NET_RAW for raw sockets
	ALSA: hda: Flush interrupts on disabling
	regulator: lm363x: Fix off-by-one n_voltages for lm3632 ldo_vpos/ldo_vneg
	ASoC: sgtl5000: Fix charge pump source assignment
	dmaengine: bcm2835: Print error in case setting DMA mask fails
	leds: leds-lp5562 allow firmware files up to the maximum length
	media: dib0700: fix link error for dibx000_i2c_set_speed
	media: exynos4-is: fix leaked of_node references
	media: hdpvr: Add device num check and handling
	sched/fair: Fix imbalance due to CPU affinity
	sched/core: Fix CPU controller for !RT_GROUP_SCHED
	x86/reboot: Always use NMI fallback when shutdown via reboot vector IPI fails
	x86/apic: Soft disable APIC before initializing it
	ALSA: hda - Show the fatal CORB/RIRB error more clearly
	ALSA: i2c: ak4xxx-adda: Fix a possible null pointer dereference in build_adc_controls()
	media: iguanair: add sanity checks
	base: soc: Export soc_device_register/unregister APIs
	ALSA: usb-audio: Skip bSynchAddress endpoint check if it is invalid
	ia64:unwind: fix double free for mod->arch.init_unw_table
	EDAC/altera: Use the proper type for the IRQ status bits
	md: don't call spare_active in md_reap_sync_thread if all member devices can't work
	md: don't set In_sync if array is frozen
	efi: cper: print AER info of PCIe fatal error
	media: gspca: zero usb_buf on error
	dmaengine: iop-adma: use correct printk format strings
	media: omap3isp: Don't set streaming state on random subdevs
	net: lpc-enet: fix printk format strings
	ARM: dts: imx7d: cl-som-imx7: make ethernet work again
	media: radio/si470x: kill urb on error
	media: hdpvr: add terminating 0 at end of string
	media: dvb-core: fix a memory leak bug
	PM / devfreq: passive: Use non-devm notifiers
	PM / devfreq: exynos-bus: Correct clock enable sequence
	media: saa7146: add cleanup in hexium_attach()
	media: cpia2_usb: fix memory leaks
	media: saa7134: fix terminology around saa7134_i2c_eeprom_md7134_gate()
	media: ov9650: add a sanity check
	ACPI / CPPC: do not require the _PSD method
	arm64: kpti: ensure patched kernel text is fetched from PoU
	nvmet: fix data units read and written counters in SMART log
	iommu/amd: Silence warnings under memory pressure
	libtraceevent: Change users plugin directory
	ARM: dts: exynos: Mark LDO10 as always-on on Peach Pit/Pi Chromebooks
	ACPI: custom_method: fix memory leaks
	ACPI / PCI: fix acpi_pci_irq_enable() memory leak
	hwmon: (acpi_power_meter) Change log level for 'unsafe software power cap'
	md/raid1: fail run raid1 array when active disk less than one
	dmaengine: ti: edma: Do not reset reserved paRAM slots
	kprobes: Prohibit probing on BUG() and WARN() address
	s390/crypto: xts-aes-s390 fix extra run-time crypto self tests finding
	ASoC: dmaengine: Make the pcm->name equal to pcm->id if the name is not set
	mmc: sdhci: Fix incorrect switch to HS mode
	libertas: Add missing sentinel at end of if_usb.c fw_table
	e1000e: add workaround for possible stalled packet
	drm/amd/powerplay/smu7: enforce minimal VBITimeout (v2)
	media: ttusb-dec: Fix info-leak in ttusb_dec_send_command()
	ALSA: hda/realtek - Blacklist PC beep for Lenovo ThinkCentre M73/93
	btrfs: extent-tree: Make sure we only allocate extents from block groups with the same type
	media: omap3isp: Set device on omap3isp subdevs
	PM / devfreq: passive: fix compiler warning
	ALSA: firewire-tascam: handle error code when getting current source of clock
	ALSA: firewire-tascam: check intermediate state of clock status and retry
	IB/hfi1: Define variables as unsigned long to fix KASAN warning
	printk: remove games with previous record flags
	printk: Do not lose last line in kmsg buffer dump
	fuse: fix missing unlock_page in fuse_writepage()
	parisc: Disable HP HSC-PCI Cards to prevent kernel crash
	KVM: x86: always stop emulation on page fault
	KVM: x86: set ctxt->have_exception in x86_decode_insn()
	KVM: x86: Manually calculate reserved bits when loading PDPTRS
	media: sn9c20x: Add MSI MS-1039 laptop to flip_dmi_table
	ASoC: Intel: NHLT: Fix debug print format
	ASoC: Intel: Fix use of potentially uninitialized variable
	ARM: zynq: Use memcpy_toio instead of memcpy on smp bring-up
	alarmtimer: Use EOPNOTSUPP instead of ENOTSUPP
	regulator: Defer init completion for a while after late_initcall
	memcg, kmem: do not fail __GFP_NOFAIL charges
	ovl: filter of trusted xattr results in audit
	Btrfs: fix use-after-free when using the tree modification log
	btrfs: Relinquish CPUs in btrfs_compare_trees
	md/raid6: Set R5_ReadError when there is read failure on parity disk
	cfg80211: Purge frame registrations on iftype change
	/dev/mem: Bail out upon SIGKILL.
	ext4: fix warning inside ext4_convert_unwritten_extents_endio
	ext4: fix punch hole for inline_data file systems
	quota: fix wrong condition in is_quota_modification()
	hwrng: core - don't wait on add_early_randomness()
	i2c: riic: Clear NACK in tend isr
	CIFS: fix max ea value size
	CIFS: Fix oplock handling for SMB 2.1+ protocols
	btrfs: qgroup: Drop quota_root and fs_info parameters from update_qgroup_status_item
	Btrfs: fix race setting up and completing qgroup rescan workers
	Linux 4.9.195

Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
2019-10-24 21:39:34 +03:00

584 lines
18 KiB
C

/**
*
* GSPCA sub driver for W996[78]CF JPEG USB Dual Mode Camera Chip.
*
* Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com>
*
* This module is adapted from the in kernel v4l1 w9968cf driver:
*
* Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/* Note this is not a stand alone driver, it gets included in ov519.c, this
is a bit of a hack, but it needs the driver code for a lot of different
ov sensors which is already present in ov519.c (the old v4l1 driver used
the ovchipcam framework). When we have the time we really should move
the sensor drivers to v4l2 sub drivers, and properly split of this
driver from ov519.c */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */
#define Y_QUANTABLE (&sd->jpeg_hdr[JPEG_QT0_OFFSET])
#define UV_QUANTABLE (&sd->jpeg_hdr[JPEG_QT1_OFFSET])
static const struct v4l2_pix_format w9968cf_vga_mode[] = {
{160, 120, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE,
.bytesperline = 160 * 2,
.sizeimage = 160 * 120 * 2,
.colorspace = V4L2_COLORSPACE_JPEG},
{176, 144, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE,
.bytesperline = 176 * 2,
.sizeimage = 176 * 144 * 2,
.colorspace = V4L2_COLORSPACE_JPEG},
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320 * 2,
.sizeimage = 320 * 240 * 2,
.colorspace = V4L2_COLORSPACE_JPEG},
{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 352 * 2,
.sizeimage = 352 * 288 * 2,
.colorspace = V4L2_COLORSPACE_JPEG},
{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 640 * 2,
.sizeimage = 640 * 480 * 2,
.colorspace = V4L2_COLORSPACE_JPEG},
};
static void reg_w(struct sd *sd, u16 index, u16 value);
/*--------------------------------------------------------------------------
Write 64-bit data to the fast serial bus registers.
Return 0 on success, -1 otherwise.
--------------------------------------------------------------------------*/
static void w9968cf_write_fsb(struct sd *sd, u16* data)
{
struct usb_device *udev = sd->gspca_dev.dev;
u16 value;
int ret;
if (sd->gspca_dev.usb_err < 0)
return;
value = *data++;
memcpy(sd->gspca_dev.usb_buf, data, 6);
/* Avoid things going to fast for the bridge with a xhci host */
udelay(150);
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
value, 0x06, sd->gspca_dev.usb_buf, 6, 500);
if (ret < 0) {
pr_err("Write FSB registers failed (%d)\n", ret);
sd->gspca_dev.usb_err = ret;
}
}
/*--------------------------------------------------------------------------
Write data to the serial bus control register.
Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/
static void w9968cf_write_sb(struct sd *sd, u16 value)
{
int ret;
if (sd->gspca_dev.usb_err < 0)
return;
/* Avoid things going to fast for the bridge with a xhci host */
udelay(150);
/* We don't use reg_w here, as that would cause all writes when
bitbanging i2c to be logged, making the logs impossible to read */
ret = usb_control_msg(sd->gspca_dev.dev,
usb_sndctrlpipe(sd->gspca_dev.dev, 0),
0,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, 0x01, NULL, 0, 500);
udelay(W9968CF_I2C_BUS_DELAY);
if (ret < 0) {
pr_err("Write SB reg [01] %04x failed\n", value);
sd->gspca_dev.usb_err = ret;
}
}
/*--------------------------------------------------------------------------
Read data from the serial bus control register.
Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/
static int w9968cf_read_sb(struct sd *sd)
{
int ret;
if (sd->gspca_dev.usb_err < 0)
return -1;
/* Avoid things going to fast for the bridge with a xhci host */
udelay(150);
/* We don't use reg_r here, as the w9968cf is special and has 16
bit registers instead of 8 bit */
ret = usb_control_msg(sd->gspca_dev.dev,
usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
1,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, 0x01, sd->gspca_dev.usb_buf, 2, 500);
if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0] |
(sd->gspca_dev.usb_buf[1] << 8);
} else {
pr_err("Read SB reg [01] failed\n");
sd->gspca_dev.usb_err = ret;
/*
* Make sure the buffer is zeroed to avoid uninitialized
* values.
*/
memset(sd->gspca_dev.usb_buf, 0, 2);
}
udelay(W9968CF_I2C_BUS_DELAY);
return ret;
}
/*--------------------------------------------------------------------------
Upload quantization tables for the JPEG compression.
This function is called by w9968cf_start_transfer().
Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/
static void w9968cf_upload_quantizationtables(struct sd *sd)
{
u16 a, b;
int i, j;
reg_w(sd, 0x39, 0x0010); /* JPEG clock enable */
for (i = 0, j = 0; i < 32; i++, j += 2) {
a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j + 1]) << 8);
b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j + 1]) << 8);
reg_w(sd, 0x40 + i, a);
reg_w(sd, 0x60 + i, b);
}
reg_w(sd, 0x39, 0x0012); /* JPEG encoder enable */
}
/****************************************************************************
* Low-level I2C I/O functions. *
* The adapter supports the following I2C transfer functions: *
* i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) *
* i2c_adap_read_byte_data() *
* i2c_adap_read_byte() *
****************************************************************************/
static void w9968cf_smbus_start(struct sd *sd)
{
w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
}
static void w9968cf_smbus_stop(struct sd *sd)
{
w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
}
static void w9968cf_smbus_write_byte(struct sd *sd, u8 v)
{
u8 bit;
int sda;
for (bit = 0 ; bit < 8 ; bit++) {
sda = (v & 0x80) ? 2 : 0;
v <<= 1;
/* SDE=1, SDA=sda, SCL=0 */
w9968cf_write_sb(sd, 0x10 | sda);
/* SDE=1, SDA=sda, SCL=1 */
w9968cf_write_sb(sd, 0x11 | sda);
/* SDE=1, SDA=sda, SCL=0 */
w9968cf_write_sb(sd, 0x10 | sda);
}
}
static void w9968cf_smbus_read_byte(struct sd *sd, u8 *v)
{
u8 bit;
/* No need to ensure SDA is high as we are always called after
read_ack which ends with SDA high */
*v = 0;
for (bit = 0 ; bit < 8 ; bit++) {
*v <<= 1;
/* SDE=1, SDA=1, SCL=1 */
w9968cf_write_sb(sd, 0x0013);
*v |= (w9968cf_read_sb(sd) & 0x0008) ? 1 : 0;
/* SDE=1, SDA=1, SCL=0 */
w9968cf_write_sb(sd, 0x0012);
}
}
static void w9968cf_smbus_write_nack(struct sd *sd)
{
/* No need to ensure SDA is high as we are always called after
read_byte which ends with SDA high */
w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
}
static void w9968cf_smbus_read_ack(struct sd *sd)
{
struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int sda;
/* Ensure SDA is high before raising clock to avoid a spurious stop */
w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
sda = w9968cf_read_sb(sd);
w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
if (sda >= 0 && (sda & 0x08)) {
PDEBUG(D_USBI, "Did not receive i2c ACK");
sd->gspca_dev.usb_err = -EIO;
}
}
/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
static void w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
{
struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
u16* data = (u16 *)sd->gspca_dev.usb_buf;
data[0] = 0x082f | ((sd->sensor_addr & 0x80) ? 0x1500 : 0x0);
data[0] |= (sd->sensor_addr & 0x40) ? 0x4000 : 0x0;
data[1] = 0x2082 | ((sd->sensor_addr & 0x40) ? 0x0005 : 0x0);
data[1] |= (sd->sensor_addr & 0x20) ? 0x0150 : 0x0;
data[1] |= (sd->sensor_addr & 0x10) ? 0x5400 : 0x0;
data[2] = 0x8208 | ((sd->sensor_addr & 0x08) ? 0x0015 : 0x0);
data[2] |= (sd->sensor_addr & 0x04) ? 0x0540 : 0x0;
data[2] |= (sd->sensor_addr & 0x02) ? 0x5000 : 0x0;
data[3] = 0x1d20 | ((sd->sensor_addr & 0x02) ? 0x0001 : 0x0);
data[3] |= (sd->sensor_addr & 0x01) ? 0x0054 : 0x0;
w9968cf_write_fsb(sd, data);
data[0] = 0x8208 | ((reg & 0x80) ? 0x0015 : 0x0);
data[0] |= (reg & 0x40) ? 0x0540 : 0x0;
data[0] |= (reg & 0x20) ? 0x5000 : 0x0;
data[1] = 0x0820 | ((reg & 0x20) ? 0x0001 : 0x0);
data[1] |= (reg & 0x10) ? 0x0054 : 0x0;
data[1] |= (reg & 0x08) ? 0x1500 : 0x0;
data[1] |= (reg & 0x04) ? 0x4000 : 0x0;
data[2] = 0x2082 | ((reg & 0x04) ? 0x0005 : 0x0);
data[2] |= (reg & 0x02) ? 0x0150 : 0x0;
data[2] |= (reg & 0x01) ? 0x5400 : 0x0;
data[3] = 0x001d;
w9968cf_write_fsb(sd, data);
data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
data[0] |= (value & 0x40) ? 0x0540 : 0x0;
data[0] |= (value & 0x20) ? 0x5000 : 0x0;
data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0);
data[1] |= (value & 0x10) ? 0x0054 : 0x0;
data[1] |= (value & 0x08) ? 0x1500 : 0x0;
data[1] |= (value & 0x04) ? 0x4000 : 0x0;
data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0);
data[2] |= (value & 0x02) ? 0x0150 : 0x0;
data[2] |= (value & 0x01) ? 0x5400 : 0x0;
data[3] = 0xfe1d;
w9968cf_write_fsb(sd, data);
PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
}
/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
static int w9968cf_i2c_r(struct sd *sd, u8 reg)
{
struct gspca_dev *gspca_dev = (struct gspca_dev *)sd;
int ret = 0;
u8 value;
/* Fast serial bus data control disable */
w9968cf_write_sb(sd, 0x0013); /* don't change ! */
w9968cf_smbus_start(sd);
w9968cf_smbus_write_byte(sd, sd->sensor_addr);
w9968cf_smbus_read_ack(sd);
w9968cf_smbus_write_byte(sd, reg);
w9968cf_smbus_read_ack(sd);
w9968cf_smbus_stop(sd);
w9968cf_smbus_start(sd);
w9968cf_smbus_write_byte(sd, sd->sensor_addr + 1);
w9968cf_smbus_read_ack(sd);
w9968cf_smbus_read_byte(sd, &value);
/* signal we don't want to read anymore, the v4l1 driver used to
send an ack here which is very wrong! (and then fixed
the issues this gave by retrying reads) */
w9968cf_smbus_write_nack(sd);
w9968cf_smbus_stop(sd);
/* Fast serial bus data control re-enable */
w9968cf_write_sb(sd, 0x0030);
if (sd->gspca_dev.usb_err >= 0) {
ret = value;
PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
} else
PERR("i2c read [0x%02x] failed", reg);
return ret;
}
/*--------------------------------------------------------------------------
Turn on the LED on some webcams. A beep should be heard too.
Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/
static void w9968cf_configure(struct sd *sd)
{
reg_w(sd, 0x00, 0xff00); /* power-down */
reg_w(sd, 0x00, 0xbf17); /* reset everything */
reg_w(sd, 0x00, 0xbf10); /* normal operation */
reg_w(sd, 0x01, 0x0010); /* serial bus, SDS high */
reg_w(sd, 0x01, 0x0000); /* serial bus, SDS low */
reg_w(sd, 0x01, 0x0010); /* ..high 'beep-beep' */
reg_w(sd, 0x01, 0x0030); /* Set sda scl to FSB mode */
sd->stopped = 1;
}
static void w9968cf_init(struct sd *sd)
{
unsigned long hw_bufsize = sd->sif ? (352 * 288 * 2) : (640 * 480 * 2),
y0 = 0x0000,
u0 = y0 + hw_bufsize / 2,
v0 = u0 + hw_bufsize / 4,
y1 = v0 + hw_bufsize / 4,
u1 = y1 + hw_bufsize / 2,
v1 = u1 + hw_bufsize / 4;
reg_w(sd, 0x00, 0xff00); /* power off */
reg_w(sd, 0x00, 0xbf10); /* power on */
reg_w(sd, 0x03, 0x405d); /* DRAM timings */
reg_w(sd, 0x04, 0x0030); /* SDRAM timings */
reg_w(sd, 0x20, y0 & 0xffff); /* Y buf.0, low */
reg_w(sd, 0x21, y0 >> 16); /* Y buf.0, high */
reg_w(sd, 0x24, u0 & 0xffff); /* U buf.0, low */
reg_w(sd, 0x25, u0 >> 16); /* U buf.0, high */
reg_w(sd, 0x28, v0 & 0xffff); /* V buf.0, low */
reg_w(sd, 0x29, v0 >> 16); /* V buf.0, high */
reg_w(sd, 0x22, y1 & 0xffff); /* Y buf.1, low */
reg_w(sd, 0x23, y1 >> 16); /* Y buf.1, high */
reg_w(sd, 0x26, u1 & 0xffff); /* U buf.1, low */
reg_w(sd, 0x27, u1 >> 16); /* U buf.1, high */
reg_w(sd, 0x2a, v1 & 0xffff); /* V buf.1, low */
reg_w(sd, 0x2b, v1 >> 16); /* V buf.1, high */
reg_w(sd, 0x32, y1 & 0xffff); /* JPEG buf 0 low */
reg_w(sd, 0x33, y1 >> 16); /* JPEG buf 0 high */
reg_w(sd, 0x34, y1 & 0xffff); /* JPEG buf 1 low */
reg_w(sd, 0x35, y1 >> 16); /* JPEG bug 1 high */
reg_w(sd, 0x36, 0x0000);/* JPEG restart interval */
reg_w(sd, 0x37, 0x0804);/*JPEG VLE FIFO threshold*/
reg_w(sd, 0x38, 0x0000);/* disable hw up-scaling */
reg_w(sd, 0x3f, 0x0000); /* JPEG/MCTL test data */
}
static void w9968cf_set_crop_window(struct sd *sd)
{
int start_cropx, start_cropy, x, y, fw, fh, cw, ch,
max_width, max_height;
if (sd->sif) {
max_width = 352;
max_height = 288;
} else {
max_width = 640;
max_height = 480;
}
if (sd->sensor == SEN_OV7620) {
/*
* Sigh, this is dependend on the clock / framerate changes
* made by the frequency control, sick.
*
* Note we cannot use v4l2_ctrl_g_ctrl here, as we get called
* from ov519.c:setfreq() with the ctrl lock held!
*/
if (sd->freq->val == 1) {
start_cropx = 277;
start_cropy = 37;
} else {
start_cropx = 105;
start_cropy = 37;
}
} else {
start_cropx = 320;
start_cropy = 35;
}
/* Work around to avoid FP arithmetics */
#define SC(x) ((x) << 10)
/* Scaling factors */
fw = SC(sd->gspca_dev.pixfmt.width) / max_width;
fh = SC(sd->gspca_dev.pixfmt.height) / max_height;
cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.pixfmt.width) / fh;
ch = (fw >= fh) ? SC(sd->gspca_dev.pixfmt.height) / fw : max_height;
sd->sensor_width = max_width;
sd->sensor_height = max_height;
x = (max_width - cw) / 2;
y = (max_height - ch) / 2;
reg_w(sd, 0x10, start_cropx + x);
reg_w(sd, 0x11, start_cropy + y);
reg_w(sd, 0x12, start_cropx + x + cw);
reg_w(sd, 0x13, start_cropy + y + ch);
}
static void w9968cf_mode_init_regs(struct sd *sd)
{
int val, vs_polarity, hs_polarity;
w9968cf_set_crop_window(sd);
reg_w(sd, 0x14, sd->gspca_dev.pixfmt.width);
reg_w(sd, 0x15, sd->gspca_dev.pixfmt.height);
/* JPEG width & height */
reg_w(sd, 0x30, sd->gspca_dev.pixfmt.width);
reg_w(sd, 0x31, sd->gspca_dev.pixfmt.height);
/* Y & UV frame buffer strides (in WORD) */
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) {
reg_w(sd, 0x2c, sd->gspca_dev.pixfmt.width / 2);
reg_w(sd, 0x2d, sd->gspca_dev.pixfmt.width / 4);
} else
reg_w(sd, 0x2c, sd->gspca_dev.pixfmt.width);
reg_w(sd, 0x00, 0xbf17); /* reset everything */
reg_w(sd, 0x00, 0xbf10); /* normal operation */
/* Transfer size in WORDS (for UYVY format only) */
val = sd->gspca_dev.pixfmt.width * sd->gspca_dev.pixfmt.height;
reg_w(sd, 0x3d, val & 0xffff); /* low bits */
reg_w(sd, 0x3e, val >> 16); /* high bits */
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) {
/* We may get called multiple times (usb isoc bw negotiat.) */
jpeg_define(sd->jpeg_hdr, sd->gspca_dev.pixfmt.height,
sd->gspca_dev.pixfmt.width, 0x22); /* JPEG 420 */
jpeg_set_qual(sd->jpeg_hdr, v4l2_ctrl_g_ctrl(sd->jpegqual));
w9968cf_upload_quantizationtables(sd);
v4l2_ctrl_grab(sd->jpegqual, true);
}
/* Video Capture Control Register */
if (sd->sensor == SEN_OV7620) {
/* Seems to work around a bug in the image sensor */
vs_polarity = 1;
hs_polarity = 1;
} else {
vs_polarity = 1;
hs_polarity = 0;
}
val = (vs_polarity << 12) | (hs_polarity << 11);
/* NOTE: We may not have enough memory to do double buffering while
doing compression (amount of memory differs per model cam).
So we use the second image buffer also as jpeg stream buffer
(see w9968cf_init), and disable double buffering. */
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) {
/* val |= 0x0002; YUV422P */
val |= 0x0003; /* YUV420P */
} else
val |= 0x0080; /* Enable HW double buffering */
/* val |= 0x0020; enable clamping */
/* val |= 0x0008; enable (1-2-1) filter */
/* val |= 0x000c; enable (2-3-6-3-2) filter */
val |= 0x8000; /* capt. enable */
reg_w(sd, 0x16, val);
sd->gspca_dev.empty_packet = 0;
}
static void w9968cf_stop0(struct sd *sd)
{
v4l2_ctrl_grab(sd->jpegqual, false);
reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */
reg_w(sd, 0x16, 0x0000); /* stop video capture */
}
/* The w9968cf docs say that a 0 sized packet means EOF (and also SOF
for the next frame). This seems to simply not be true when operating
in JPEG mode, in this case there may be empty packets within the
frame. So in JPEG mode use the JPEG SOI marker to detect SOF.
Note to make things even more interesting the w9968cf sends *PLANAR* jpeg,
to be precise it sends: SOI, SOF, DRI, SOS, Y-data, SOS, U-data, SOS,
V-data, EOI. */
static void w9968cf_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
if (w9968cf_vga_mode[gspca_dev->curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) {
if (len >= 2 &&
data[0] == 0xff &&
data[1] == 0xd8) {
gspca_frame_add(gspca_dev, LAST_PACKET,
NULL, 0);
gspca_frame_add(gspca_dev, FIRST_PACKET,
sd->jpeg_hdr, JPEG_HDR_SZ);
/* Strip the ff d8, our own header (which adds
huffman and quantization tables) already has this */
len -= 2;
data += 2;
}
} else {
/* In UYVY mode an empty packet signals EOF */
if (gspca_dev->empty_packet) {
gspca_frame_add(gspca_dev, LAST_PACKET,
NULL, 0);
gspca_frame_add(gspca_dev, FIRST_PACKET,
NULL, 0);
gspca_dev->empty_packet = 0;
}
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}