cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pac207.c (12921B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Pixart PAC207BCA library
      4 *
      5 * Copyright (C) 2008 Hans de Goede <hdegoede@redhat.com>
      6 * Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
      7 * Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
      8 *
      9 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
     10 */
     11
     12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     13
     14#define MODULE_NAME "pac207"
     15
     16#include <linux/input.h>
     17#include "gspca.h"
     18/* Include pac common sof detection functions */
     19#include "pac_common.h"
     20
     21MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
     22MODULE_DESCRIPTION("Pixart PAC207");
     23MODULE_LICENSE("GPL");
     24
     25#define PAC207_CTRL_TIMEOUT		100  /* ms */
     26
     27#define PAC207_BRIGHTNESS_MIN		0
     28#define PAC207_BRIGHTNESS_MAX		255
     29#define PAC207_BRIGHTNESS_DEFAULT	46
     30#define PAC207_BRIGHTNESS_REG		0x08
     31
     32#define PAC207_EXPOSURE_MIN		3
     33#define PAC207_EXPOSURE_MAX		90 /* 1 sec expo time / 1 fps */
     34#define PAC207_EXPOSURE_DEFAULT		5 /* power on default: 3 */
     35#define PAC207_EXPOSURE_REG		0x02
     36
     37#define PAC207_GAIN_MIN			0
     38#define PAC207_GAIN_MAX			31
     39#define PAC207_GAIN_DEFAULT		7 /* power on default: 9 */
     40#define PAC207_GAIN_REG			0x0e
     41
     42#define PAC207_AUTOGAIN_DEADZONE	30
     43
     44/* global parameters */
     45static int led_invert;
     46module_param(led_invert, int, 0644);
     47MODULE_PARM_DESC(led_invert, "Invert led");
     48
     49/* specific webcam descriptor */
     50struct sd {
     51	struct gspca_dev gspca_dev;		/* !! must be the first item */
     52
     53	struct v4l2_ctrl *brightness;
     54
     55	u8 mode;
     56	u8 sof_read;
     57	u8 header_read;
     58	u8 autogain_ignore_frames;
     59
     60	atomic_t avg_lum;
     61};
     62
     63static const struct v4l2_pix_format sif_mode[] = {
     64	{176, 144, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
     65		.bytesperline = 176,
     66		.sizeimage = (176 + 2) * 144,
     67			/* uncompressed, add 2 bytes / line for line header */
     68		.colorspace = V4L2_COLORSPACE_SRGB,
     69		.priv = 1},
     70	{352, 288, V4L2_PIX_FMT_PAC207, V4L2_FIELD_NONE,
     71		.bytesperline = 352,
     72			/* compressed, but only when needed (not compressed
     73			   when the framerate is low) */
     74		.sizeimage = (352 + 2) * 288,
     75		.colorspace = V4L2_COLORSPACE_SRGB,
     76		.priv = 0},
     77};
     78
     79static const __u8 pac207_sensor_init[][8] = {
     80	{0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0x84},
     81	{0x49, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
     82	{0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
     83	{0x32, 0x00, 0x96, 0x00, 0xa2, 0x02, 0xaf, 0x00},
     84};
     85
     86static void pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
     87	const u8 *buffer, u16 length)
     88{
     89	struct usb_device *udev = gspca_dev->dev;
     90	int err;
     91
     92	if (gspca_dev->usb_err < 0)
     93		return;
     94
     95	memcpy(gspca_dev->usb_buf, buffer, length);
     96
     97	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x01,
     98			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
     99			0x00, index,
    100			gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
    101	if (err < 0) {
    102		pr_err("Failed to write registers to index 0x%04X, error %d\n",
    103		       index, err);
    104		gspca_dev->usb_err = err;
    105	}
    106}
    107
    108static void pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
    109{
    110	struct usb_device *udev = gspca_dev->dev;
    111	int err;
    112
    113	if (gspca_dev->usb_err < 0)
    114		return;
    115
    116	err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
    117			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
    118			value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
    119	if (err) {
    120		pr_err("Failed to write a register (index 0x%04X, value 0x%02X, error %d)\n",
    121		       index, value, err);
    122		gspca_dev->usb_err = err;
    123	}
    124}
    125
    126static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
    127{
    128	struct usb_device *udev = gspca_dev->dev;
    129	int res;
    130
    131	if (gspca_dev->usb_err < 0)
    132		return 0;
    133
    134	res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00,
    135			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
    136			0x00, index,
    137			gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
    138	if (res < 0) {
    139		pr_err("Failed to read a register (index 0x%04X, error %d)\n",
    140		       index, res);
    141		gspca_dev->usb_err = res;
    142		return 0;
    143	}
    144
    145	return gspca_dev->usb_buf[0];
    146}
    147
    148/* this function is called at probe time */
    149static int sd_config(struct gspca_dev *gspca_dev,
    150			const struct usb_device_id *id)
    151{
    152	struct cam *cam;
    153	u8 idreg[2];
    154
    155	idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
    156	idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
    157	idreg[0] = ((idreg[0] & 0x0f) << 4) | ((idreg[1] & 0xf0) >> 4);
    158	idreg[1] = idreg[1] & 0x0f;
    159	gspca_dbg(gspca_dev, D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X\n",
    160		  idreg[0], idreg[1]);
    161
    162	if (idreg[0] != 0x27) {
    163		gspca_dbg(gspca_dev, D_PROBE, "Error invalid sensor ID!\n");
    164		return -ENODEV;
    165	}
    166
    167	gspca_dbg(gspca_dev, D_PROBE,
    168		  "Pixart PAC207BCA Image Processor and Control Chip detected (vid/pid 0x%04X:0x%04X)\n",
    169		  id->idVendor, id->idProduct);
    170
    171	cam = &gspca_dev->cam;
    172	cam->cam_mode = sif_mode;
    173	cam->nmodes = ARRAY_SIZE(sif_mode);
    174
    175	return 0;
    176}
    177
    178/* this function is called at probe and resume time */
    179static int sd_init(struct gspca_dev *gspca_dev)
    180{
    181	u8 mode;
    182
    183	/* mode: Image Format (Bit 0), LED (1), Compr. test mode (2) */
    184	if (led_invert)
    185		mode = 0x02;
    186	else
    187		mode = 0x00;
    188	pac207_write_reg(gspca_dev, 0x41, mode);
    189	pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
    190
    191	return gspca_dev->usb_err;
    192}
    193
    194static void setcontrol(struct gspca_dev *gspca_dev, u16 reg, u16 val)
    195{
    196	pac207_write_reg(gspca_dev, reg, val);
    197	pac207_write_reg(gspca_dev, 0x13, 0x01);	/* Bit 0, auto clear */
    198	pac207_write_reg(gspca_dev, 0x1c, 0x01);	/* not documented */
    199}
    200
    201static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
    202{
    203	struct gspca_dev *gspca_dev =
    204		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
    205	struct sd *sd = (struct sd *)gspca_dev;
    206
    207	gspca_dev->usb_err = 0;
    208
    209	if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
    210		/* when switching to autogain set defaults to make sure
    211		   we are on a valid point of the autogain gain /
    212		   exposure knee graph, and give this change time to
    213		   take effect before doing autogain. */
    214		gspca_dev->exposure->val    = PAC207_EXPOSURE_DEFAULT;
    215		gspca_dev->gain->val        = PAC207_GAIN_DEFAULT;
    216		sd->autogain_ignore_frames  = PAC_AUTOGAIN_IGNORE_FRAMES;
    217	}
    218
    219	if (!gspca_dev->streaming)
    220		return 0;
    221
    222	switch (ctrl->id) {
    223	case V4L2_CID_BRIGHTNESS:
    224		setcontrol(gspca_dev, PAC207_BRIGHTNESS_REG, ctrl->val);
    225		break;
    226	case V4L2_CID_AUTOGAIN:
    227		if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
    228			setcontrol(gspca_dev, PAC207_EXPOSURE_REG,
    229				   gspca_dev->exposure->val);
    230		if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
    231			setcontrol(gspca_dev, PAC207_GAIN_REG,
    232				   gspca_dev->gain->val);
    233		break;
    234	default:
    235		return -EINVAL;
    236	}
    237	return gspca_dev->usb_err;
    238}
    239
    240static const struct v4l2_ctrl_ops sd_ctrl_ops = {
    241	.s_ctrl = sd_s_ctrl,
    242};
    243
    244/* this function is called at probe time */
    245static int sd_init_controls(struct gspca_dev *gspca_dev)
    246{
    247	struct sd *sd = (struct sd *) gspca_dev;
    248	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
    249
    250	gspca_dev->vdev.ctrl_handler = hdl;
    251	v4l2_ctrl_handler_init(hdl, 4);
    252
    253	sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
    254				V4L2_CID_BRIGHTNESS,
    255				PAC207_BRIGHTNESS_MIN, PAC207_BRIGHTNESS_MAX,
    256				1, PAC207_BRIGHTNESS_DEFAULT);
    257	gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
    258				V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
    259	gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
    260				V4L2_CID_EXPOSURE,
    261				PAC207_EXPOSURE_MIN, PAC207_EXPOSURE_MAX,
    262				1, PAC207_EXPOSURE_DEFAULT);
    263	gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
    264				V4L2_CID_GAIN,
    265				PAC207_GAIN_MIN, PAC207_GAIN_MAX,
    266				1, PAC207_GAIN_DEFAULT);
    267	if (hdl->error) {
    268		pr_err("Could not initialize controls\n");
    269		return hdl->error;
    270	}
    271	v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
    272	return 0;
    273}
    274
    275/* -- start the camera -- */
    276static int sd_start(struct gspca_dev *gspca_dev)
    277{
    278	struct sd *sd = (struct sd *) gspca_dev;
    279	__u8 mode;
    280
    281	pac207_write_reg(gspca_dev, 0x0f, 0x10); /* Power control (Bit 6-0) */
    282	pac207_write_regs(gspca_dev, 0x0002, pac207_sensor_init[0], 8);
    283	pac207_write_regs(gspca_dev, 0x000a, pac207_sensor_init[1], 8);
    284	pac207_write_regs(gspca_dev, 0x0012, pac207_sensor_init[2], 8);
    285	pac207_write_regs(gspca_dev, 0x0042, pac207_sensor_init[3], 8);
    286
    287	/* Compression Balance */
    288	if (gspca_dev->pixfmt.width == 176)
    289		pac207_write_reg(gspca_dev, 0x4a, 0xff);
    290	else
    291		pac207_write_reg(gspca_dev, 0x4a, 0x30);
    292	pac207_write_reg(gspca_dev, 0x4b, 0x00); /* Sram test value */
    293	pac207_write_reg(gspca_dev, 0x08, v4l2_ctrl_g_ctrl(sd->brightness));
    294
    295	/* PGA global gain (Bit 4-0) */
    296	pac207_write_reg(gspca_dev, 0x0e,
    297		v4l2_ctrl_g_ctrl(gspca_dev->gain));
    298	pac207_write_reg(gspca_dev, 0x02,
    299		v4l2_ctrl_g_ctrl(gspca_dev->exposure)); /* PXCK = 12MHz /n */
    300
    301	/* mode: Image Format (Bit 0), LED (1), Compr. test mode (2) */
    302	if (led_invert)
    303		mode = 0x00;
    304	else
    305		mode = 0x02;
    306	if (gspca_dev->pixfmt.width == 176) {	/* 176x144 */
    307		mode |= 0x01;
    308		gspca_dbg(gspca_dev, D_STREAM, "pac207_start mode 176x144\n");
    309	} else {				/* 352x288 */
    310		gspca_dbg(gspca_dev, D_STREAM, "pac207_start mode 352x288\n");
    311	}
    312	pac207_write_reg(gspca_dev, 0x41, mode);
    313
    314	pac207_write_reg(gspca_dev, 0x13, 0x01); /* Bit 0, auto clear */
    315	pac207_write_reg(gspca_dev, 0x1c, 0x01); /* not documented */
    316	msleep(10);
    317	pac207_write_reg(gspca_dev, 0x40, 0x01); /* Start ISO pipe */
    318
    319	sd->sof_read = 0;
    320	sd->autogain_ignore_frames = 0;
    321	atomic_set(&sd->avg_lum, -1);
    322	return gspca_dev->usb_err;
    323}
    324
    325static void sd_stopN(struct gspca_dev *gspca_dev)
    326{
    327	u8 mode;
    328
    329	/* mode: Image Format (Bit 0), LED (1), Compr. test mode (2) */
    330	if (led_invert)
    331		mode = 0x02;
    332	else
    333		mode = 0x00;
    334	pac207_write_reg(gspca_dev, 0x40, 0x00); /* Stop ISO pipe */
    335	pac207_write_reg(gspca_dev, 0x41, mode); /* Turn off LED */
    336	pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */
    337}
    338
    339
    340static void pac207_do_auto_gain(struct gspca_dev *gspca_dev)
    341{
    342	struct sd *sd = (struct sd *) gspca_dev;
    343	int avg_lum = atomic_read(&sd->avg_lum);
    344
    345	if (avg_lum == -1)
    346		return;
    347
    348	if (sd->autogain_ignore_frames > 0)
    349		sd->autogain_ignore_frames--;
    350	else if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
    351			90, PAC207_AUTOGAIN_DEADZONE))
    352		sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
    353}
    354
    355static void sd_pkt_scan(struct gspca_dev *gspca_dev,
    356			u8 *data,
    357			int len)
    358{
    359	struct sd *sd = (struct sd *) gspca_dev;
    360	unsigned char *sof;
    361
    362	sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
    363	if (sof) {
    364		int n;
    365
    366		/* finish decoding current frame */
    367		n = sof - data;
    368		if (n > sizeof pac_sof_marker)
    369			n -= sizeof pac_sof_marker;
    370		else
    371			n = 0;
    372		gspca_frame_add(gspca_dev, LAST_PACKET,
    373				data, n);
    374		sd->header_read = 0;
    375		gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
    376		len -= sof - data;
    377		data = sof;
    378	}
    379	if (sd->header_read < 11) {
    380		int needed;
    381
    382		/* get average lumination from frame header (byte 5) */
    383		if (sd->header_read < 5) {
    384			needed = 5 - sd->header_read;
    385			if (len >= needed)
    386				atomic_set(&sd->avg_lum, data[needed - 1]);
    387		}
    388		/* skip the rest of the header */
    389		needed = 11 - sd->header_read;
    390		if (len <= needed) {
    391			sd->header_read += len;
    392			return;
    393		}
    394		data += needed;
    395		len -= needed;
    396		sd->header_read = 11;
    397	}
    398
    399	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
    400}
    401
    402#if IS_ENABLED(CONFIG_INPUT)
    403static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
    404			u8 *data,		/* interrupt packet data */
    405			int len)		/* interrupt packet length */
    406{
    407	int ret = -EINVAL;
    408
    409	if (len == 2 && data[0] == 0x5a && data[1] == 0x5a) {
    410		input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
    411		input_sync(gspca_dev->input_dev);
    412		input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
    413		input_sync(gspca_dev->input_dev);
    414		ret = 0;
    415	}
    416
    417	return ret;
    418}
    419#endif
    420
    421/* sub-driver description */
    422static const struct sd_desc sd_desc = {
    423	.name = MODULE_NAME,
    424	.config = sd_config,
    425	.init = sd_init,
    426	.init_controls = sd_init_controls,
    427	.start = sd_start,
    428	.stopN = sd_stopN,
    429	.dq_callback = pac207_do_auto_gain,
    430	.pkt_scan = sd_pkt_scan,
    431#if IS_ENABLED(CONFIG_INPUT)
    432	.int_pkt_scan = sd_int_pkt_scan,
    433#endif
    434};
    435
    436/* -- module initialisation -- */
    437static const struct usb_device_id device_table[] = {
    438	{USB_DEVICE(0x041e, 0x4028)},
    439	{USB_DEVICE(0x093a, 0x2460)},
    440	{USB_DEVICE(0x093a, 0x2461)},
    441	{USB_DEVICE(0x093a, 0x2463)},
    442	{USB_DEVICE(0x093a, 0x2464)},
    443	{USB_DEVICE(0x093a, 0x2468)},
    444	{USB_DEVICE(0x093a, 0x2470)},
    445	{USB_DEVICE(0x093a, 0x2471)},
    446	{USB_DEVICE(0x093a, 0x2472)},
    447	{USB_DEVICE(0x093a, 0x2474)},
    448	{USB_DEVICE(0x093a, 0x2476)},
    449	{USB_DEVICE(0x145f, 0x013a)},
    450	{USB_DEVICE(0x2001, 0xf115)},
    451	{}
    452};
    453MODULE_DEVICE_TABLE(usb, device_table);
    454
    455/* -- device connect -- */
    456static int sd_probe(struct usb_interface *intf,
    457			const struct usb_device_id *id)
    458{
    459	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
    460				THIS_MODULE);
    461}
    462
    463static struct usb_driver sd_driver = {
    464	.name = MODULE_NAME,
    465	.id_table = device_table,
    466	.probe = sd_probe,
    467	.disconnect = gspca_disconnect,
    468#ifdef CONFIG_PM
    469	.suspend = gspca_suspend,
    470	.resume = gspca_resume,
    471	.reset_resume = gspca_resume,
    472#endif
    473};
    474
    475module_usb_driver(sd_driver);